Introdução aos Commands

Entre as várias novidades que o WPF introduziu, uma das que mais vieram para nos ajudar são os Commands, que é semelhante ao popular design pattern Command do GoF. A Microsoft implementou este padrão no WPF para permitir uma melhor organização do código, já que ações são executadas quando o usuário manuseia algum controle ou quando alguma tecla (ou uma combinação delas) for pressionada.

Para ilustrar o problema que temos atualmente, vamos imaginar que temos um controle ListBox com o nome dos clientes e um Button que em seu evento Click, recupera o item selecionado, e exibe os detalhes cadastrais deste em um Label mais abaixo. Além disso, há um item na ToolBar da aplicação que tem a mesma funcionalidade, mas além, ainda possibilita que pressionando as teclas Ctrl + D, também deverá ter o mesmo efeito, ou seja, de mostrar os detalhes do cliente selecionado. Basicamente o código seria qualquer coisa próximo disso:

private void butto1_Click(object sender, EventArgs e)
{
    this.ExibirDetalhesDoCliente();
}

private void menuItem1_Click(object sender, EventArgs e)
{
    this.ExibirDetalhesDoCliente();
}

private void ExibirDetalhesDoCliente()
{
    if (this.Clientes.SelectedItem != null)
    {
        this.DetalhesDoCliente.Text = this.Clientes.SelectedItem.ToString();
    }
}

A imagem abaixo ilustra o formulário já em funcionamento:

Imagine também que gostaria de algo mais interativo, como por exemplo, fazer com que o botão que exibe os detalhes do cliente altere entre o estado de habilitado e desabilitado, de acordo com a seleção (ou não) de um item do ListBox. Isso faria com que eu espalhasse pelo código, verificações e checagens para garantir este resultado. Dependendo de como faz isso, pode resultar em um código ruim e propício a muitas redundâncias. Além disso, muitas vezes você tem várias outras ações, que são executadas por um formulário, e podem ser reutilizadas por vários controles dentro do mesmo, ou até mesmo em outros formulários dentro da mesma aplicação.

Como há muitas ações que são acessadas através de vários controles do formulário, pode também ter condicionais que estão ligados a elas, que permite a execução de acordo com alguma regra (como ter um item selecionado no ListBox). Outro ponto importante é a execução em batch, onde você pode elencar várias ações, adicionando cada uma delas na medida que vai clicando ou manipulando algum controle.

Essa funcionalidade fornecida pelo WPF tem a finalidade de conseguir controlar, de uma forma mais elegante e eficaz, esse tipo de situação, que é muito comum em aplicações Windows. A ideia é que esse padrão separa a execução da ação (chamada daqui para frente de comando) daquele que a invoca, ou seja, no evento Click por exemplo, você não terá mais o código, mas o comando será vinculado ao controle que o executará. Dessa forma, esta técnica permitirá que você vincule o mesmo comando à vários controles, mas a implementação somente acontecerá uma única vez.

O primeiro tipo que vamos analisar, é a interface ICommand. Essa interface fornece três membros autoexplicativos: Execute, CanExecute e CanExecuteChanged. O que chama mais a atenção é o método CanExecute, que retorna um valor boleano indicando se o comando poderá ou não ser executado (através do método Execute). No nosso exemplo, o comando deverá avaliar se o ListBox possui algum item selecionado, para que assim conseguimos visualizar os detalhes do mesmo.

Atualmente no WPF somente existe uma única classe que implementa esta interface, que é a RoutedCommand, e por tabela, a RoutedUICommand, que herda da RoutedCommand. Esse tipo de comando leva esse nome porque trabalha de forma semelhante aos routed events, ou seja, se o controle atual não for capaz de executar o comando, ele delega para o próximo elemento da árvore, até que alguém o execute. A única diferença entre as classes RoutedCommand e RoutedUICommand é que a segunda fornece uma propriedade chamada Text, que nada mais é do que a descrição do comando, que é usado para ser exibido por algum controle de UI.

Para começarmos a modificar o código acima, aquele para exibição de detalhes do cliente, vamos criar uma instância da classe RoutedUICommand, configurando em seu construtor o nome do comando e o tipo da classe onde ela é criada. Note que o modelo de criação segue mais ou menos a mesma forma de criação das dependency properties e dos routed events. Logo após a criação, note que estamos adicionando a possibilidade de utilizar uma combinação de teclas para executar o comando, através da coleção de gestures:

public static class MeusComandos
{
    public static readonly RoutedUICommand ExibirDetalhesDoCliente;

    static MeusComandos()
    {
        ExibirDetalhesDoCliente = 
            new RoutedUICommand(“Exibir Cliente”, “ExibirDetalhesDoCliente”, typeof(MeusComandos));
        ExibirDetalhesDoCliente.InputGestures.Add(new KeyGesture(Key.D, ModifierKeys.Control));
    }
}

É importante dizer que o controle por si só não faz nada. Depois de decidir onde irá usá-lo, você precisa determinar o que ele irá fazer e se ele pode ou não executar esse comando. Para vincular o comando à algum controle, você precisará fazer uso dos CommandBindings. CommandBindings é uma espécie de listeners que aguardam um determinado comando ser executado, e utilizará os métodos já conhecidos (CanExecute e Execute) quando este comando for acionado. Repare no código abaixo, que em momento nenhum o código relacionado ao comando está vinculado ao controle; o que vinculamos no(s) controle(s) é o comando que ele deverá executar, através de um command binding.

public partial class Window1 : Window
{
    public Window1()
    {
        InitializeComponent();
        this.ConfigurarComandos();
    }

    private void ConfigurarComandos()
    {
        this.CommandBindings.Add(
            new CommandBinding(
                MeusComandos.ExibirDetalhesDoCliente,
                cb_Executed,
                cb_CanExecute));

        this.button1.Command = MeusComandos.ExibirDetalhesDoCliente;
        this.menuItem1.Command = MeusComandos.ExibirDetalhesDoCliente;
    }

    private void cb_Executed(object sender, ExecutedRoutedEventArgs e)
    {
        this.label1.Content =
            ((ListBoxItem)this.listBox1.SelectedItem).Content.ToString();
    }

    private void cb_CanExecute(object sender, CanExecuteRoutedEventArgs e)
    {
        e.CanExecute = this.listBox1.SelectedItem != null;
    }
}

A classe CommandBinding fornece vários eventos, e entre eles os eventos CanExecute e Executed, que é exatamente onde colocamos a regra para determinar se o comando pode ser executado, e o código referente ao comando propriamente dito, que no nosso caso, é mostrar os detalhes. Note que vinculamos a instância no comando criado (ExibirDetalhesDoCliente) na propriedade Command (exposta pela interface ICommandSource) do controle Button e do Menu, que por sua vez, recebe a instância de alguma classe que implemente a interface ICommand. Repare que não estamos nos vinculamos ao evento Click dos controles, pois internamente, depois deste evento (Click) disparado, o WPF avalia se a propriedade Command está definida com algum comando, e estando, o executará, extraindo dos command bindings quais são os eventos correspondentes ao comando. Como estamos lidando com eventos aqui, a propriedade CanExecute defina no parâmetro CanExecuteRoutedEventArgs, é que recebe essa resposta e encaminha para o WPF avaliar, e se estiver True, o executará. O código acima fica mais simples de ler, centraliza as regras e facilita a manutenção.

Algo interessante a se notar é que os controles que estão com o comando vinculado, monitoram o retorno do método/evento CanExecute, definindo a sua respectiva propriedade Enabled com o resultado deste método, ou seja, deixará o controle desabilitado até que ele retorna True. A imagem abaixo ilustra esse comportamento. Do lado esquerdo, a imagem está com os dois controles (Menu e Button) desabilitados até o momento que seleciono um dos itens do ListBox, que é a imagem da direita. Ao clicar no Menu, no Button ou pressionar Ctrl + D, o nome selecionado aparecerá no Label.

É interessante dizer também que os command bindings podem ser definidos de forma declarativa, através do XAML, eliminando assim todo o código que está definido dentro do método ConfigurarComandos.

<Window … xmlns:local=”clr-namespace:WpfApplication1″>
    <Window.CommandBindings>
        <CommandBinding
            Command=”local:MeusComandos.ExibirDetalhesDoCliente”
            CanExecute=”b_CanExecute”
            Executed=”b_Executed” />
    </Window.CommandBindings>

    <Grid>
        <Button Command=”local:MeusComandos.ExibirDetalhesDoCliente” … />
        <Menu Name=”menu1″>
            <MenuItem Header=”Cadastro”>
                <MenuItem
                    Name=”menuItem1″
                    Command=”local:MeusComandos.ExibirDetalhesDoCliente” />
            </MenuItem>
        </Menu>
    </Grid>
</Window>

Comandos Predefinidos

Há alguns comandos que já são bastante conhecidos, como é caso do Copiar, Colar, Recortar, etc., e a Microsoft mapeou eles e já embutiu no WPF, distribuindo-os em cinco categorias: ApplicationCommands, ComponentCommands, MediaCommands, NavigationCommands e EditingCommands. Cada categoria nada mais é do que uma classe estática e, consequentemente, todos os comandos também são declarados como estático, o que siginifica que haverá apenas uma única instância compartilhada de cada um com toda a aplicação.

Pelo fato dos controles serem estáticos (mesmo aquele que criamos acima), quem o “traz” para o controle atual é o CommandBinding, evitando conflitos entre outras regiões que fazem uso deste mesmo comando. Abaixo temos um exemplo simples de como podemos utilizar o comando Copy/Paste, expostos pela classe ApplicationCommands:

<Window …>
    <Window.CommandBindings>
        <CommandBinding
            Command=”ApplicationCommands.Copy”
            CanExecute=”CommandBinding_CanExecute” />
    </Window.CommandBindings>

    <Grid>
        <TextBox Name=”textBox1″ />

        <Button Name=”button1″ Command=”ApplicationCommands.Copy” />
        <Button Name=”button2″ Command=”ApplicationCommands.Paste” />
    </Grid>
</Window>

E no C#, você precisa apenas testar se há algo digitado no TextBox e se ele está selecionado:

private void CommandBinding_CanExecute(object sender, CanExecuteRoutedEventArgs e)
{
    e.CanExecute = !string.IsNullOrEmpty(this.textBox1.SelectedText);
}

É interessante notar que em momento nenhum eu escrevi código para mandar o conteúdo selecionado para o ClipBoard ou para ler o conteúdo de lá. Esse código já está criado em outro lugar (no próprio sistema operacional), e o que o WPF faz é uma forma de interceptar e me permitir decidir de devo ou não continuar.

Conclusão: Eis mais uma grande funcionalidade que facilita muito a escrita de código no desenvolvimento de aplicações Windows. Além disso, torna o código mais fácil para dar manutenção, já que a centralização é um dos principais trunfos desta técnica.

Twitter

Recentemente eu criei uma conta no Twitter. Na verdade eu não uso aquilo como deveria ser, apenas utilizo para divulgar novos artigos e posts que publico. Se você já assina este RSS, em princípio, me seguir no Twitter é redundante.

Serialização de Datasets

Vira e mexe alguém entra em contato comigo para discutir sobre – os populares – DataSets. Como todos sabem, ele foi construído para ambientes desconectados, que permite criar uma espécie de “banco de dados em memória”, possibilitando ao usuário chegar de manhã na empresa, carregar os dados que ele vai trabalhar durante todo o dia, e depois sair à campo.

Durante o tempo que ele estiver fora, dificilmente terá acesso à rede da empresa, o que obriga a persistir os dados fisicamente, para quando chegar no(s) cliente(s), conseguir restaurar essas informações e manipulá-las como se ele estivesse trabalhando localmente. Dependendo do volume de informações que é carregado neste DataSet, o arquivo final pode ser muito grande, e dependendo do tipo de dispositivo que está utilizando, isso pode ser prejudicial.

Hoje um ex-aluno me enviou um e-mail dizendo que passava por um problema semelhante, onde ele precisava diminuir o tamanho final do arquivo que continha os dados. O problema é que ele estava utilizando a serialização em Xml, que naturalmente é maior do que a serialização binária. Isso se deve-se ao fato de que Xml é o padrão para interoperabilidade, e se fosse trafegá-lo através de Web Services, então obrigatoriamente ele deve ser serializado desta forma.

Do contrário, você pode optar pelo padrão binário. Como neste caso a interoperabilidade não é necessária, já que a finalidade é apenas ter um arquivo menor salvo no disco, podemos adotar esta técnica. Para isso, a partir da versão 2.0 do ADO.NET, a Microsoft disponibilizou uma pequena funcionalidade no DataSet, que modifica-o durante o processo de serialização. Abaixo o exemplo de como podemos proceder:

DataSet ds = new DataSet();
CarregarDados(ds);

ds.RemotingFormat = SerializationFormat.Binary;

using (FileStream fs = File.Create(“Dados.bin”))
    new BinaryFormatter().Serialize(fs, ds);

Com este exemplo, um DataSet que em Xml tem 1MB, caiu para 280KB. Você não é obrigado a utilizar a propriedade RemotingFormat, mas se omití-la, verá que o resultado não será tão expressivo como. Quando você define esta propriedade, ele customizará a serialização, transformando o schema e a instância do DataSet atual em um formato mais otimizado e comprimido. Atente-se aqui, pois se o DataSet for muito pequeno (quantidade de linhas/colunas), o resultado pode ser igual ou até mesmo maior que o Xml.

Mais uma vez, se possível reescreva e tente optar por alguma outra alternativa que não sejam os DataSets. Quando você persite-o, independentemente se for Xml ou binário, ele armazena muito mais informações do que o aquilo que realmente você precisa, pois lembre-se: ele é um “banco de dados em memória”. Para mais informações sobre serialização, consulte o capítulo 06 deste livro.

Introdução aos Routed Events

Assim como as Dependency Properties, uma outra grande inovação no WPF foram os Routed Events. As dependency properties adicionam às propriedades uma série de recursos adicionais, quando comparadas às propriedades tradicionais do .NET Framework, e o mesmo acontece com os routed events, fornecendo recursos bastantes interessantes, trazendo uma riqueza maior para os eventos, e que o WPF faz uso intenso disso.

Antes de efetivamente falar sobre os routed events, primeiro precisamos conhecer dois conceitos: logical e visual trees. Ambos tem a finalidade de descrever a interface que foi criada de forma declarativa ou imperativa, mas diferem na forma como visualizamos esses elementos. No primeiro caso, logical, cada elemento dentro desta árvore será visualizado de forma “macro”, por exemplo, se tiver um controle do tipo Button, ele será apenas um Button com uma string que representa o seu texto; já o segundo conceito, visual, faz com que ao invés de visualizarmos o controle como um todo, ele “explode” o mesmo, permitindo o acesso a cada objeto que compõe a construção dele, e no caso do Button, teríamos o Button -> ButtonChrome -> ContentPresenter -> TextBlock.

Os conceitos que vimos acima é importante, pois tanto para dependency properties quanto para os routed events, eles utilizam a árvore lógica para a propagação de informações (dependency properties) e de ações (routed events). Como vimos acima, o Button é composto de vários outros sub-elementos, mas quando o usuário efetua o clique no botão, muito provavelmente ele poderá clicar em cima do TextBlock, e sendo assim, como o WPF traduzirá, ou melhor, entregará este evento para o evento Click do botão correspondente? Tudo isso graças ao recurso de propagação de eventos através da árvore visual.

A implementação de um routed event é bem semelhante a forma que criamos uma dependency property, ou seja, o evento é definido através de uma classe chamada RoutedEvent, declarada como estática e marcada como readonly no topo da classe onde ele será exposto. No construtor estático desta mesma classe, utilizamos o método estático RegisterRoutedEvent da classe EventManager, onde especificamos o nome do evento, a estratégia de roteamento, o tipo do event handler e o tipo da classe onde ele está sendo criado. Abaixo temos uma implementação de um evento em um controle:

public partial class MeuControle : UserControl
{
    public static readonly RoutedEvent ChangedStateEvent;

    static MeuControle()
    {
        ChangedStateEvent =
            EventManager.RegisterRoutedEvent(
                “ChangedState”,
                RoutingStrategy.Tunnel, 
                typeof(RoutedEventHandler), 
                typeof(MeuControle));
    }

    public event RoutedEventHandler ChangedState
    {
        add { AddHandler(MeuControle.ChangedStateEvent, value); }
        remove { RemoveHandler(MeuControle.ChangedStateEvent, value); }
    }

    private void button1_Click(object sender, RoutedEventArgs e)
    {
        this.RaiseEvent(new RoutedEventArgs(MeuControle.ChangedStateEvent, this));
    }
}

O primeiro ponto importante a se notar, é a nomenclatura do evento. Por convenção, adotou-se sufixar com a palavra “Event”, mas isso fica coerente quando estamos criando tudo em inglês; se o nome do evento for “EstadoAlterado”, eu considero desnecessário este sufixo. Além disso, temos um evento tradicional do .NET, chamado de ChangedState. Isso serve apenas como um wrapper para o routed event que foi criado acima (lembre-se que as dependency properties também são expostas através de um wrapper), interceptando a adição e remoção do delegate que tratará o evento, recorrendo aos métodos AddHandler e RemoveHandler, respectivamente, que foram herdados da classe UIElement. E, finalmente, chega o momento de disparar o evento, e para isso utilizamos o método RaiseEvent, que dado os argumentos (falaremos mais abaixo sobre eles) correspondente ao delegate do evento, ele irá dispará-lo e os interessados poderão se anexar ao mesmo.

Os routed events nos permite ainda vincular à um evento não necessariamente em cima do próprio controle, mas através de qualquer controle dentro da hierarquia. Por exemplo, se tivermos um formulário WPF, e dentro dele um StackPanel, e dois botões dentro deste painel, o XAML correspondente seria:

<Window …>
    <Grid>
        <StackPanel>
            <Button Name=”btn1″ Click=”btn1_Click”>Botao 1</Button>
            <Button Name=”btn2″ Click=”btn2_Click”>Botao 2</Button>
        </StackPanel>
    </Grid>
</Window>

A pergunta é: onde tratar o evento Click de cada botão? Se eu tratar o evento diretamente no botão (que é o mais comum), isso fará com que eu crie um event handler para cada botão dentro do StackPanel. Então porque não centralizar isso, onde independemente de qual botão for clicado, eu redirecionará sempre para o mesmo event handler? Poderia resolver isso vinculando o evento Click de todos os botões para o mesmo event handler, mas uma forma mais simples de fazer isso, é vinculando o evento ao controle que está acima na hierarquia do XAML, por exemplo:

<Window …>
    <Grid>
        <StackPanel ButtonBase.Click=”AlgumBotaoFoiClicado”>
            <Button Name=”btn1″>Botao 1</Button>
            <Button Name=”btn2″>Botao 2</Button>
        </StackPanel>
    </Grid>
</Window>

Mas e se haverem mais do que um StackPanel dentro do meu formulário? Podemos então elevar o tratamento do evento para nível de formulário, como é mostrado abaixo:

<Window … ButtonBase.Click=”AlgumBotaoFoiClicado”>
    <Grid>
        <StackPanel>
            <Button Name=”btn1″>Botao 1</Button>
            <Button Name=”btn2″>Botao 2</Button>
        </StackPanel>
        <StackPanel>
            <Button Name=”btn3″>Botao 3</Button>
            <Button Name=”btn4″>Botao 4</Button>
        </StackPanel>
    </Grid>
</Window>

O que determina como esses eventos serão disparados/propagados, é a estratégia de roteamento que você define quando cria o evento. Para isso, utilizamos o enumerador RoutingStrategy, que podemos escolher uma entre as três opções abaixo:

  • Tunnel: O evento é primeiramente disparado no controle raiz e depois em cima de todos os elementos até chegar no controle que efetivamente disparou o evento.
  • Bubble: O evento é primeiramente disparado no controle que efetivamente disparou o evento, subindo até a raiz.
  • Direct: O evento somente é disparado em cima do elemento de origem, assim como acontece com os eventos tradicionais do .NET.

Para utilizar o controle que criamos acima e consumir o evento, teremos um código semelhante a este:

<Window …
    xmlns:app=”clr-namespace:WpfApplication1″
    app:MeuControle.ChangedState=”MeuControle_ChangedState”>
    <Grid>
        <app:MeuControle ChangedState=”MeuControle_ChangedState” />
    </Grid>
</Window>

private void MeuControle_ChangedState(object sender, RoutedEventArgs e)
{
    MessageBox.Show(“Sender: ” + sender.ToString());
}

Se o evento for criado com a opção Tunnel, as mensagens serão: “Window1” e “MeuControle”; se definir a opção como Bubble, as mensagens serão “MeuControle” e “Window1” e, finalmente, se definir como Direct, somente aparecerá “MeuControle”.

A assinatura dos event handlers dos routed events seguem, basicamente, o mesmo padrão de eventos tradicionais do .NET. O primeiro parâmetro (sender) é do tipo System.Object, que informa o objeto que disparou o evento. Já o segundo parâmetro (e) é uma classe do tipo RoutedEventArgs, que expõe quatro propriedades que trazem informações contextuais:

  • Source: System.Object que representa o elemento na árvore lógica que originalmente invocou o evento.
  • OriginalSource: System.Object que representa o elemento na árvore visual que originalmente disparou o evento.
  • Handled: Valor boleano que indica se o evento deverá prosseguir com a propagação para os elementos subsequentes da árvore. Se definí-lo como False, o próximo não será disparado.
  • RoutedEvent: A instância do routed event que foi disparado, que pode ser usado quando você direciona vários eventos para o mesmo event handler.

Conclusão: Assim como já acontece com as dependency properties, em um primeiro momento, esse tipo de evento torna o código um pouco mais complicado de ler, mas por outro lado, traz uma série de benefícios que você não consegue com os eventos tradicionais do .NET.

MEF – Managed Extensibility Framework

revista mundo .net - 018 Toda aplicação que deseja suportar “plugins”, terá que se preocupar, também, em criar toda a infraestrutura necessária para suportá-los. Como essa preocupação está cada vez mais popular nos dias de hoje, a Microsoft trabalha em um projeto chamado MEF – Managed Extensibility Framework. Ao invés de explicitamente referenciar os componentes na aplicação, o MEF permitirá efetuar o descobrimento desses componentes de forma implícita, através de composição, gerenciando tudo o que for preciso para manter essas extensões, possibilitando que sua aplicação fique dependente de uma abstração, e não de uma implementação.

Atualmente o MEF encontra-se em desenvolvimento, e a Microsoft tem disponibilizado versões CTPs (Community Technology Preview), para avaliações do produto. A versão atual é a CTP 8, que já vem incorporada no Beta 2 do Visual Studio .NET 2010 e .NET Framework 4.0 e, provavelmente, fará parte da versão final do .NET Framework 4.0.

Este artigo tem a finalidade de abordar a API do MEF, mostrando todas as suas funcionalidades e como podemos utilizá-las em nossas aplicações.

Introdução às Dependency Properties

Quando desenvolvemos classes e/ou controles, geralmente expomos as suas características através de propriedades. Na maioria das vezes, essas propriedades encapsulam o acesso à membros privados internos, interceptando a escrita e leitura dos mesmos. Os controles ASP.NET geralmente não possuem esses membros internos, e armazenam o conteúdo diretamente no ViewState ou no ControlState da respectiva página.

As propriedades também são utilizadas por controles Windows Forms, seguindo a mesma estratégia das propriedades tradicionais que as linguagens disponibilizam. Mas aplicações Windows geralmente tem algumas características próprias, como validação e, principalmente, databinding, que é a possibilidade de vincular um objeto à algum controle de interface (UI). Há também algumas tarefas que são comuns em aplicações deste tipo, como por exemplo, a notificação da alteração de um valor, que fará eventuais mudanças nos demais controles.

Para tornar esse trabalho mais suave, a Microsoft introduziu, desde a primeira versão do WPF, as Dependency Properties. Esse tipo especial de propriedade é semelhante as propriedades das linguagens, mas com muito mais poder. A inteligência envolvida neste novo tipo de propriedade, permite trabalharmos com o código puramente declarativo (XAML), sem precisar de qualquer código procedural para efetuar alguma mudança na aparência quando algo acontecer.

Além disso, temos uma série de outros benefícios ao utilizá-las. O primeiro deles é a capacidade de sermos notificados quando o valor dessa propriedade for alterado, e o próprio sistema de Triggers do WPF faz uso desta funcionalidade, onde você consegue associar um valor à uma propriedade, e quando ela receber este valor, você poderá tomar alguma decisão, como alterar a cor de outro controle, disparo de outros eventos, etc. Há também outros pontos positivos que vamos analisar mais tarde, ainda neste artigo.

A sua utilização é relativamente simples, e não dispensa completamente o uso das propriedades tradicionais fornecidas pelas linguagens. As classes (ou controles) que querem fazer uso destas propriedades, deverão herdar direta ou indiretamente da classe DependencyObject, pois essa classe permitirá ao objeto participar do serviço de propriedades que o WPF disponibiliza. Além disso, para que uma propriedade seja registrada e, consequentemente, poder fazer uso de toda essa infraestrutura, cada propriedade exposta deverá manter um campo dentro da classe onde ela será declarada, definindo o tipo deste campo como sendo DependencyProperty. Abaixo temos a estrutura de uma dependency property:

public static readonly DependencyProperty TitleProperty =
    DependencyProperty.Register(
        “Title”, 
        typeof(string), 
        typeof(MeuControle));

public string Title
{
    get
    {
        return this.GetValue(TitleProperty).ToString();
    }
    set
    {
        this.SetValue(TitleProperty, value);
    }
}

O primeiro ponto que vemos é que a classe DependencyProperty não é instanciada diretamente. Para registrá-la, você precisa invocar o método estático Register (dessa mesma classe), que em sua versão mais básica, receberá o nome da propriedade, o tipo da propriedade e o tipo onde essa propriedade está sendo criada. Outro ponto bastante curioso é que esse campo é declarado como estático. Mas e se houverem várias instâncias dessa classe, o valor da propriedade será compartilhado? Não. Na verdade, as propriedades são salvas em uma espécie de dicionário, onde a chave deverá ser única dentro do tipo. Aqui é a grande diferença, ou seja, ao invés de termos um campo privado para cada propriedade exposta, que muitas vezes ficavam com o seu valor padrão, as dependency properties resolvem este problema armazenando somente os valores que são modificados pela instância, enquanto as outras compartilham um – mesmo – valor padrão, reutilizando o valor padrão por todas as instâncias.

A seguir temos a propriedade Title, que por sua vez, serve apenas como um wrapper para o objeto que criamos acima, expondo o tipo efetivo da propriedade, que no caso acima é string. Note que em momento nenhum você acessa o objeto TitleProperty diretamente; toda a manipulação é realizada pelos métodos GetValue e SetValue, para ler e escrever, respectivamente. Como vimos, esses métodos estão disponíveis para todas as classes que derivam da classe DependencyObject, que realiza todas as etapas necessárias para determinar se o valor já foi sobrescrito pela instância corrente, e caso tenha sido, este será retornado ao invés de seu valor padrão.

Ainda há a possibilidade de registrar uma dependency property como somente leitura, pois pode haver propriedades que apenas reportam o estado interno da classe, como por exemplo, a propriedade IsMouseOver da classe Control, que retorna um valor boleano indicando se o ponteiro está ou não posicionado em cima daquele controle. Neste caso, o valor é definido internamente pelo WPF.

A classe DependencyProperty fornece para essa finalidade, um método também estático, chamado RegisterReadOnly, que depois de registrado, retornará uma instância da classe DependencyPropertyKey, representando a chave para a propriedade recém registrada.

private static readonly DependencyPropertyKey TitlePropertyKey =
      DependencyProperty.RegisterReadOnly(
          “Title”, 
          typeof(string),
          typeof(MeuControle));
 
public static readonly DependencyProperty TitleProperty =
      TitlePropertyKey.DependencyProperty;

public string Title
{
    get
    {
        return this.GetValue(TitleProperty).ToString();
    }
    private set
    {
        this.SetValue(TitlePropertyKey, value);
    }
}

Neste caso, veja que a chave é declarada de forma privada, para que somente o interior da classe onde ela é declarada tenha acesso. A criação do objeto DependencyProperty ainda é necessário, mas não será através do método Register. A classe DependencyPropertyKey define uma propriedade chamada DependencyProperty, que retorna a propriedade para acessá-la através do método GetValue, seguindo o mesmo esquema que vimos acima. Na propriedade Title, a escrita também está protegida pelo modificador private, e note que a alteração está sendo feita, passando o chave e não a instância da DependencyProperty como fizemos no primeiro exemplo.

Metadados

Como vimos acima, a classe DependencyProperty ainda fornece outras versões (overloads) do método Register. O que veremos a seguir, é aquele que recebe os metadados. Através destes metadados, poderemos configurar uma série de características destas propriedades, como por exemplo: valor padrão, notificação quando o valor for alterado, coerção, etc. A principal classe que podemos utilizar para definição destes metadados, é a FrameworkPropertyMetadata.

Entre as principais funcionalidades que esta classe fornece, temos a possibilidade de informar o valor padrão da propriedade, e enquanto você não definir um novo valor para uma propriedade, será este valor que será retornado. Além disso, podemos definir através de delegates, ações que desejamos executar quando o valor for alterado ou alguma ação para efetuar uma coerção no valor. Abaixo temos o exemplo de como utilizar esses metadados:

public static readonly DependencyProperty TitleProperty =
    DependencyProperty.Register(
        “Title”,
        typeof(string),
        typeof(MeuControle),
        new FrameworkPropertyMetadata(
            “Título Indefinido”,
            (o, e) => MessageBox.Show(e.NewValue.ToString()),
            (d, e) => string.Format(“*** {0} ***”, e)));

O primeiro parâmetro informado no construtor da classe FrameworkPropertyMetadata, é o valor padrão da propriedade. Esse parâmetro é do tipo System.Object, pois a propriedade poderá ser de qualquer tipo. Todas as instâncias desta classe sempre compartilharão este mesmo valor, a menos que uma instância específica o sobrescreva, e a partir daí, esta instância terá o seu próprio valor.

Os dois parâmetros seguintes são delegates, onde o primeiro deles (PropertyChangedCallback) representa o método que será disparado quando o valor desta propriedade for alterado. O argumento “e” é do tipo DependencyPropertyChangedEventArgs, e entre suas propriedades, temos OldValue e NewValue, que são autoexplicativas. Já o terceiro parâmetro (CoerceValueCallback), define um método de coerção, que tem a finalidade de customizar/formatar a entrada da informação de acordo com alguma regra, que acontecerá antes de armazenar o valor definitivamente. O “e” que vemos sendo passado para este método, traz o valor atual; a assinatura deste delegate também retorna um System.Object, que é justamente o valor depois de alterado.

Validação

Outro ponto importante quando falamos sobre propriedades, é a questão de validação. As validações geralmente são avaliadas antes do valor ser efetivamente armazenado. As dependency properties também já trazem a validação nativamente, que podemos configurar e vincular durante a criação de uma propriedade.

Para isso, o método Register ainda fornece em um de seus overloads, um parâmetro do tipo ValidateValueCallback, que também é um delegate e que recebe o valor que está sendo passado para a propriedade e retorna um valor boleano, indicando se o parâmetro está válido ou não. O seu uso está sendo exibido abaixo, e note que antes da propriedade receber o valor, a consistência para verificar se ele está correta será avaliada, e caso retorne False, uma exceção será disparada.

public static readonly DependencyProperty TitleProperty =
    DependencyProperty.Register(
        “Title”,
        typeof(string),
        typeof(MeuControle),
        new FrameworkPropertyMetadata(
            “Sem Título Definido”,
            (o, e) => MessageBox.Show(e.NewValue.ToString()),
            (d, e) => string.Format(“*** {0} ***”, e)),
        p => p != null && p.ToString().Length > 0);

Conclusão: Apesar de no primeiro momento tornar o código um pouco ilegível, percebermos no decorrer deste artigo o poder deste tipo de propriedade. Grande parte das tarefas de manipulação de UI, e que antes ficavam espalhadas pelo código, agora podemos centralizar, tornando a manutenção e reutilização muito mais simples. Isso sem contar que utilizar esse tipo de propriedade habilita grande parte dos recursos exclusivos do WPF, como estilos, databinding, etc.

Exceções no construtor e blocos using

Se uma determinada classe que está sendo criada possuir referências para outros objetos que são custosos, a boa prática é implementar o padrão Disposable, que nos permite explicitamente descartar estes recursos quando não mais precisamos deles. O padrão Disposable consiste na implementação de uma interface chamada IDisposable, que fornece um método Dispose, que dentro dele você fará toda a limpeza necessária.

Disparar exceções em construtores é algo comum, e que na maioria das vezes representam validações dos parâmetros que são passados à instância da classe que está sendo criada. Um cuidado especial nestes casos, é garantir que você nunca armazene nenhum objeto antes de tais validações, por exemplo:

public class MinhaClasse : IDisposable
{
    private IntPtr _ponteiro;
    private string _valor;

    public MinhaClasse(string valor, IntPtr ponteiro)
    {
        this._ponteiro = ponteiro;

        if (string.IsNullOrEmpty(valor))
            throw new ArgumentNullException(“valor”);

        this._valor = valor;
    }

    public void Dispose()
    {
        if (this._ponteiro != IntPtr.Zero)
            this._ponteiro = IntPtr.Zero;
    }

    ~MinhaClasse() { Dispose(); }
}

Ao criar a instância desta classe e definir o parâmetro valor como nulo, repare que antes da validação acontecer, o membro _ponteiro já estará com o valor armazenado. Mesmo que você esteja trabalhando da forma politicamente correta, que é implementando a interface IDisposable para a liberação dos recursos, você tem ainda outros problemas, já que ela não funciona por si só. Sabemos que a implementação desta interface é apenas uma convenção, mas para que a limpeza realmente funcione, o desenvolvedor deverá explicitamente invocar o método Dispose.

Neste caso, envolver a instância em um bloco using (que garante a chamada implícita do Dispose) não resolverá. Como sabemos, o using é açúcar sintático, pois na verdade ele é compilado para blocos try/finally. Se instanciarmos a classe dentro do using, a criação da instância será colocada fora do bloco try, e como a exceção está sendo disparada no construtor, o Dispose não será invocado e, infelizmente, teremos que esperar até o destrutor ser invocado, isso se o tivermos implementado.

UserNames com autenticação Basic

Há algum tempo em comentei aqui sobre as opções de segurança no WCF, e mais tarde, como customizá-la para receber e validar usernames e passwords em um repositório qualquer. Antes da versão 3.5 do WCF, essa customização somente trabalha com segurança em nível de mensagem. Com o 3.5, a Microsoft adicionou esse suporte para também trabalhar com segurança em nível de transporte.

Isso é útil em cenários onde queremos utilizar a autenticação Basic do HTTP como meio de fornecimento das credenciais, mas ao invés da conta informada existir e de ser validada dentro do sistema operacional, vamos customizar essa regra, utilizando um repositório customizado, como uma base de dados, evitando que os clientes tenham, obrigatoriamente, contas cadastradas dentro do Windows.

Para que isso funcione, a configuração de segurança do binding deverá ser definida como Transport, e a forma de fornecimento de credenciais como Basic. Além disso, você também precisará implementar um validador customizado, herdando da classe abstrata UserNamePasswordValidator, como eu já mostrei neste artigo. Abaixo temos a configuração do lado do serviço:

<bindings>
  <basicHttpBinding>
    <binding name=”bindingConfig”>
      <security mode=”Transport”>
        <transport clientCredentialType=”Basic”/>
      </security>
    </binding>
  </basicHttpBinding>
</bindings>

Apenas lembre-se de que o Basic faz com que as credenciais sejam trafegadas codificadas e não criptografadas, e justamente por isso, estamos recorrendo à segurança em nível transporte (que neste caso é o HTTPS), para garantir a integridade e confidencialidade da mensagem e das credenciais. Para informar as credenciais do lado do cliente, você faz da mesma forma que antes:

using (Servico p = new Servico)
{
    p.ClientCredentials.UserName.UserName = “IA”;
    p.ClientCredentials.UserName.Password = “123”;

    Console.WriteLine(p.Ping(“teste”));
}

O único problema desta técnica, é que você não poderá hospedar o serviço no IIS. Isso se deve ao fato de que quando o atributo clientCredentialType estiver definido como Basic, o IIS fará a verificação durante o carregamento do serviço, analisando se o modo de autenticação Basic está habilitado para aquele diretório virtual, e caso contrário, uma exceção do tipo NotSupportedException será disparada, informando que o modo Basic não está habilitado.

Só que se você habilitá-lo, o problema volta a acontecer, pois a ideia por trás desta técnica, é utilizar o Basic como forma de envio das credenciais, mas não de validá-las, e com isso, se você colocar um usuário e senha que não existe dentro do Windows, ele não deixará você acessar o serviço, e mesmo que você digite um usuário/senha válidos, a implementação da classe UserNamePasswordValidator nunca será executada. Para que isso seja possível, você precisa modificar o pipeline do ASP.NET, acoplando módulos customizados que farão esse trabalho.

Compartilhamento de Bindings

Quando você possui múltiplos endpoints para expor um serviço, na maioria das vezes, esses endpoints possuem características diferentes, pois você poderá publicá-lo através de HTTP para consumo externo, enquanto as aplicações locais, consomem este mesmo serviço através de TCP, para uma melhor performance.

A configuração abaixo ilustra a exposição de um mesmo serviço e de um mesmo contrato através dos protocolos TCP e HTTP. Cada um dos protocolos possuem características diferentes de comunicação, e justamente por isso, exigem bindings diferentes.

<system.serviceModel>
  <services>
    <service name=”App.Servico”>
      <host>
        <baseAddresses>
          <add baseAddress=”net.tcp://localhost:9838″/>
          <add baseAddress=”http://localhost:8478″/&gt;
        </baseAddresses>
      </host>
      <endpoint address=”srv”
                contract=”App.IContrato1″
                binding=”netTcpBinding”/>
      <endpoint address=”srv”
                contract=”App.IContrato1″
                binding=”basicHttpBinding”/>
    </service>
  </services>
</system.serviceModel>

Cada endpoint é composto por um endereço, binding e contrato, e cada endpoint possui seu próprio listener e channel stack, que varia de acordo com o binding escolhido. Em algumas situações, é comum ter mais do que um contrato para o mesmo serviço, onde queremos compartilhar o mesmo endereço para ambos contratos. Abaixo podemos ver um serviço que tem esse comportamento:

<system.serviceModel>
  <services>
    <service name=”App.Servico”>
      <host>
        <baseAddresses>
          <add baseAddress=”net.tcp://localhost:9838″/>
        </baseAddresses>
      </host>
      <endpoint address=”srv”
                contract=”App.IContrato1″
                binding=”netTcpBinding”/>
      <endpoint address=”srv”
                contract=”App.IContrato2″
                binding=”netTcpBinding”/>
    </service>
  </services>
</system.serviceModel>

Repare que temos dois contratos (IContrato1 e IContrato2) expostos através de TCP e usando o mesmo endereço. Isso somente é possível porque o WCF reutiliza a mesma instância do binding para efetuar a comunicação, e difere a execução baseando-se nas Soap Actions. Se cada binding tiver sua configuração específica (definido através do atributo bindingConfiguration), então isso fará com que o WCF crie instâncias diferentes do mesmo binding, resultando em uma exceção tipo do InvalidOperationException sendo disparada, informando que não é permitido associar uma mesma instância binding à endereços diferentes.

Se você tiver endereços distintos, então duas instâncias distintas do binding correspondente serão criadas para atender cada um deles. Esse mesmo cuidado você precisa ter ao configurar o serviço de forma imperativa. Ao chamar o método AddServiceEndpoint da classe ServiceHost, você deverá se preocupar em passar a mesma instância do binding, como por exemplo:

using (ServiceHost host = 
       new ServiceHost(typeof(Servico), new Uri[] { new Uri(“net.tcp://localhost:9838”) }))
{
    NetTcpBinding b = new NetTcpBinding();

    host.AddServiceEndpoint(typeof(IContrato1), b, “srv”);
    host.AddServiceEndpoint(typeof(IContrato2), b, “srv”);

    host.Open();
    Console.ReadLine();
}

Threading em WPF

Quando desenvolvemos aplicações Windows, é muito comum em algum ponto da mesma, que algumas tarefas mais complicadas e custosas sejam realizadas, que podem levar um tempo maior até que seja concluída. Independentemente do que ela faça, seja um cálculo, uma consulta em uma base de dados ou uma chamada para um serviço, se você executar esse código de forma síncrona, o usuário deverá esperar até que essa tarefa seja finalizada, para a partir daí, conseguir acessar outras áreas do sistema.

Ao rodar uma aplicação Windows, um processo é criado dentro do sistema operacional. Processo não executa nenhum código; são as threads que fazem isso. Quando o processo é criado, uma thread é criada juntamente com ele, e esta é muitas vezes chamada de main-thread (thread principal). Essa thread nasce e morre com o término do processo, ou seja, enquanto ela estiver executando alguma tarefa, o processo continuará ativo.

As aplicações Windows que conhecemos, como Windows Forms, Console, Windows Services e WPF trabalham nesta mesma linha. Aplicações que possuem gráficos, como é o caso do Windows Forms e do WPF, tem um agravante: a afinidade que os controles tem com a thread principal. Quando a aplicação é iniciada, a thread principal é quem cria os controles (Form, TextBox, Label, TextBlock, etc.), e quando dizemos que há uma afinidade, isso quer dizer que podemos somente manipular esses controles, através da mesma thread que os criaram, e qualquer tentativa de fazer isso através de uma segunda thread, uma exceção do tipo InvalidOperationException será disparada.

Quando essas tarefas são finalizadas, é normal queremos exibir o resultado para o usuário, que na maioria das vezes, implica em alterar a propriedade Text de algum controle, exibir uma MessageBox, etc. Em Windows Forms, todos os controles herdam direta ou indiretamente da classe Control, que fornece um método chamado Invoke, e que dado um delegate, executa o método relacionado na mesma thread do criador. Mais tarde, com o .NET Framework 2.0, surgiu o SynchronizationContext, que facilitou bastante a atualização dos controles a partir de uma thread secundária.

Agora temos o WPF, que traz novas funcionalidades e uma forma um pouco diferente para lidar com esse tipo de problema. Vamos a partir deste artigo, explorar um pouco mais sobre o modelo de threading do WPF. A Microsoft introduziu uma série de novos tipos, espalhados por vários namespaces e que serão utilizados para conseguir atingir o nosso principal objetivo. Para iniciar, o primeiro tipo que temos que conhecer é a classe Dispatcher. Essa classe serve como um gerenciador de tarefas para serem executadas, e está sempre associada com uma determinada thread de UI. Ela mantém uma fila de tarefas que são executadas utilizando a thread qual está relacionada.

A fila que é mantida pela classe Dispatcher é priorizada, que permite especificar uma prioridade antes de enfileirar a tarefa (mais detalhes abaixo). Para alistar uma tarefa nesta fila, você poderá utilizar o método Invoke ou BeginInvoke. A diferença entre eles é clara: o primeiro executa a tarefa de forma síncrona, enquanto a segunda alista a tarefa para ser executada de forma assíncrona. E para sedimentar, ambas sempre executarão na thread ao qual o Dispatcher está vinculado.

Grande parte das classes que compõem o framework do WPF, incluindo os controles, herda direta ou indiretamente da classe abstrata DispatcherObject, que possui uma estrutura simples, ou seja, fornece uma propriedade chamada Dispatcher que retorna a instância de uma classe Dispatcher, e como já era de esperar, fornece a instância do Dispatcher que está vinculado com aquele classe/controle.

A classe DispatcherObject ainda fornece dois métodos importantes: CheckAccess e VerifyAccess. A diferença entre eles é que o primeiro retorna um valor boleano, indicando se a thread que está chamando tem direito de acesso ao Dispatcher correspondente. Já o segundo método, VerifyAccess, dispara uma exceção do tipo InvalidOperationException, caso a thread que está chamando não tiver direito de acesso ao Dispatcher. Como pudemos perceber, esses métodos vão nos auxiliar para determinar se há ou não a necessidade de atualizar o controle através da thread atual, sem que seja necessário utilizar o Dispatcher para chegar até o controle.

Para exemplificar, imagine que temos uma thread que executará algum cálculo complexo, e depois de calculado, deverá exibir o resultado em um TextBox. Como comentado acima, dentro desta thread não podemos alterar qualquer propriedade do TextBox, e para solucionar isso no WPF, vamos recorrer a propriedade Dispatcher do TextBox (“txt”), que foi herdada de DispatcherObject. Ao passar um delegate para o método Invoke, ele será executado (de forma síncrona) na mesma thread que criou o controle.

new Thread(() =>
{
    int result = 2 ^ 4 * 2 + 3 / 3;
    Thread.Sleep(3000); //Simula Processo Complexo

    txt.Dispatcher.Invoke(new Action<int>(r => txt.Text = r.ToString()), result);
}).Start();

Se desejar, podemos trocar o método Invoke por BeginInvoke, e a atualização do controle será feita em background. A vantagem desta técnica é que você pode executar a atualização do controle enquanto faz outras tarefas. É importante que você mantenha tarefas “leves” dentro do Dispatcher, pois tudo o que ele deveria fazer ali é atualizar a UI; colocar tarefas mais complexas, voltará a ter concorrência com os eventos dos controles e, consequentemente, o usuário voltará a ter os travamentos das telas do sistema, que acontecia quando trabalhávamos de forma síncrona.

Quando você opta por utilizar o método BeginInvoke, ele retorna uma instância da classe DispatcherOperation. Basicamente, este objeto representa uma espécie de “ponteiro” para a operação que está sendo executada. Essa classe fornece uma série de membros interessantes, e entre eles temos:

  • Dispatcher: O Dispatcher relacionado.
  • Priority: Uma das opções definidas no enumerador DispatcherPriority, que define a prioridade da operação.
  • Result: Retorna um System.Object com o resultado da tarefa (isso quando ela retornar algum resultado).
  • Status: Uma das opções definidas no enumerador DispatcherOperationStatus, que define o status atual da operação (Pending, Aborted, Completed ou Execution).
  • Abort: Método que aborta a operação que está sendo executada.
  • Wait: Quando invocado, fará um “join” na thread atual, aguardando até o término da operação. Opcionalmente você pode especificar um timeout.
  • Aborted: Evento que é disparado quando a operação é abortada.
  • Completed: Evento que é disparado quando a operação foi finalizada.

Com a instância do DispatcherOperation em mãos, podemos utilizar duas formas para chegar até o resultado, que é via eventos ou através de polling. Utilizando o modelo de eventos, podemos nos vincular ao evento Completed, e quando a operação for finalizada, esse evento será automaticamente disparado. Já o polling consiste em testar, de tempo em tempo, se a operação finalizou ou não. Abaixo temos os dois exemplos de utilização:

new Thread(() =>
{
    int result = 2 ^ 4 * 2 + 3 / 3;
    Thread.Sleep(3000); //Simula Processo Complexo

    DispatcherOperation op =
        txt.Dispatcher.BeginInvoke(new Action<int>(r => txt.Text = r.ToString()), result);

    op.Completed += (o, args) => MessageBox.Show(“Finalizou Tudo”);
}).Start();

new Thread(() =>
{
    int result = 2 ^ 4 * 2 + 3 / 3;
    Thread.Sleep(3000); //Simula Processo Complexo

    DispatcherOperation op =
        txt.Dispatcher.BeginInvoke(new Action<int>(r => txt.Text = r.ToString()), result);

    //Faz Algo…

    while (op.Status != DispatcherOperationStatus.Completed)
    {
        if (op.Wait(TimeSpan.FromSeconds(5)) == DispatcherOperationStatus.Completed)
        {
            //Finalizou a Atualização da UI
            break;
        }
    }
}).Start();

Tanto o método Invoke quanto o BeginInvoke possui versões (overloads) destes métodos que permitem especificar uma prioridade, e para isso, utilizamos uma das doze opções definidas pelo enumerador DispatcherPriority. Há algumas opções interessantes, como por exemplo Inactive, que permite você alistar a operação, mas que não será processada. De qualquer forma, na maioria das vezes a opção Normal (que também é o padrão), já será o suficiente. Abaixo um exemplo de como podemos proceder para especificar a prioridade de uma operação:

txt.Dispatcher.BeginInvoke(new Action<int>(r => txt.Text = r.ToString()), DispatcherPriority.Normal, result);

Uma vez que você tem operações alistadas no Dispatcher, o runtime irá determinar quando executá-las, dependendo da prioridade definida. A classe Dispatcher também fornece métodos para abortar todas as operações pendentes de processamento. Para isso, recorremos aos métodos InvokeShutdown ou BeginInvokeShutdown (a diferença entre eles já é sabida). A classe Dispatcher ainda fornece um evento chamado ShutdownFinished, que é disparado quando shutdown do Dispatcher for completamente finalizado, e com isso, você poderá tomar alguma decisão.

Conclusão: Como vimos, ambas tecnologias (Windows Forms e WPF) possuem os mesmos comportamentos. Como trabalhar com ambientes multi-threading não é uma tarefa fácil, a Microsoft introduziu no WPF uma forma diferente de se trabalhar para a atualizar de UI através de uma segunda thread. Além de um modelo suavemente diferente, há algumas melhorias internas que garantem que isso acabe sendo executado de uma forma melhor. E para finalizar, essa técnica visa sempre tornar a aplicação mais amigável para o usuário, sem que eles tenha experiências ruins.