O mecanismo de DataBinding, não é novo já existe há algum tempo, mais diferente do mecanismo de DataBinding tradicional, dentro da arquitetura WPF o DataBinding traz alguns recursos diferenciados e que tornam o mesmo, um mecanismo extremamente poderoso, eficaz e que tem papel muito importante na Arquitetura WPF e na construção de aplicativos com esta tecnologia. Neste primeiro artigo estaremos apresentando em detalhes, como tirar proveito deste recursos extremamente poderoso.

O DataBinding no WPF, entre muitas outras coisas, dispõe de propriedades que tem suporte nativo ao binding, uma representação flexível de dados para o usuário, permite classificar, filtrar e além destas características permite uma clara separação da lógica de negócios da interface com o usuário.

O DataBinding

A definição de databinding é simples: “é o processo de conectar o aplicativo de interface com o usuário a lógica de negócios”. Embora seja simples esta definição, realizar esta conexão envolve tarefas como validação, conexão com a fonte de dados, apresentação correta e organizada das informações para uma melhor visualização. E uma grande vantagem do binding dentro do WPF, é que ele traz uma vasta gama de propriedades e fontes de dados que podem ser utilizadas nas aplicações. Vamos começar a entender melhor como este mecanismo funciona. Observe a figura abaixo:

img

A figura acima ilustra o processo de databinding. Veja que é simples, porém muito poderoso o mecanismo de binding. Vamos começar a identificar as peças dentro deste processo. Sempre existirá um objeto fonte (Source) e um objeto alvo (Target) . Independente do alvo ou fonte o mecanismo de binding sempre seguirá o esquema ilustrado acima. O mecanismo de binding é composto além dos objetos de fonte e destino, por mais dois outros elementos, que são a propriedade de destino e um caminho para o valor no objeto fonte (source) para uso, totalizando ao todo quatro elementos. Observe a figura abaixo:

img

Identificando na figura acima:

  1. Objeto utilizado como fonte de dados (Source) .
  2. Objeto de alvo (Target) .
  3. Propriedade que terá seu valor utilizado pelo objeto de alvo (Target) , ou seja, o valor desta propriedade é o Path, ou, o caminho em que se encontra o valor a ser utilizado.
  4. Propriedade de destino (Target) , ou seja, a propriedade que receberá o valor da propriedade do objeto utilizado como fonte de dados.

Estes quatro elementos, são as peças chaves do mecanismo de binding. Os objetos podem até ser alvos e fontes diferentes, mais de qualquer maneira eles sempre irão se enquadrar neste mecanismo: Objeto Fonte (Source) , Objeto alvo (Target) , propriedade fonte e propriedade de destino.

O DataBinding e a direção do fluxo dos dados

Um dos diferenciais do binding na arquitetura WPF é a maneira como o fluxo de dados trafega entre o alvo (Target) e o Fonte (source) . O fluxo de dados pode ser OneWay, TwoWay e OneWayToSource. Observe a figura abaixo.

img

O fato de existir diversas formas de direcionar o fluxo dos dados, se deve ao fato das necessidades que existem de comunicação do usuário e a fonte de dados. Você pode, por exemplo, desejar que o usuário ao realizar uma atualização, venha propagar a mesma para a fonte de dados, ou objeto que é a fonte de dados somente atualiza o objeto alvo e não deseja ser notificada se o usuário realiza uma alteração, enfim de acordo com a necessidade, você especifica como será a direção do fluxo de dados. Veja a descrição abaixo de cada uma das formas de trafegar o fluxo de dados;

  • OneWay – Faz com que a propriedade de origem (source) atualize automaticamente a propriedade de destino (target) , mais não notifica a propriedade de origem caso haja uma atualização na propriedade de destino.
  • TwoWay- Faz com que tanto a propriedade de origem (source) ou destino (target) , sejam notificadas caso haja uma alteração em uma ou outra. Este tipo de fluxo de dados é indicado para cenários mais iterativos, quando existe uma necessidade de que atualizações sejam refletidas automaticamente, ou seja, na fonte (source) ou no destino (target) que pode ser, um formulário por exemplo.
  • OneWayToSource- É o inverso do OneWay, permitindo somente que a propriedade de destino (Target) atualize a propriedade fonte (Source) .
  • OneTime - Embora não ilustrada acima, o OneTime é utilizado quando você deseja inicializar a propriedade de destino, mais qualquer atualização posterior não seja refletida. Podemos dizer que o OneTime, é um OneWay mais simples.

Você pode especificar o tipo de fluxo de dados, através da propriedade Mode da classe Binding:


<Bnding Mode=OneWay />

O que faz propagar a atualização da fonte

Agora que entendemos como funciona o fluxo dos dados entre a fonte e o destino, precisamos saber o que faz desencadear esta atualização ou estas notificações de mudança.

Os fluxos OneWayToSource e TwoWay, escutam mudanças na propriedade de destino (target) e propagam até a fonte de dados (source) , isto é chamado de atualização da fonte. Mais como se dá esta atualização? É simples a propriedade UpdateSourceTrigger da classe Binding, é responsável por especificar como irá ocorrer esta notificação.

Observe a figura abaixo:

img

Se o valor da propriedade UpdateSourceTrigger for PropertyChanged, a fonte (source) é atualizado caso haja mudança na propriedade de destino (Target) . Se o valor e UpdateSourceTrigger for LostFocus, a fonte é atualiza do com o novo valor, assim que a propriedade de destino (Target) perde o foco.



Bom pessoal, nesta primeira parte, aprendemos o conceito do binding, a direção do fluxo de dados, como é desencadeada a atualização da fonte de dados e tivemos uma pequena introdução sobre esta importante funcionalidade do WPF. Mais fiquem ligados ainda temos que aprender sobre como criar o binding, binding com coleções, validação enfim tem muita coisa boa por vir.



Seguimos no aprendizado sobre a arquitetura WPF. E nesta segunda parte do estudo sobre o Databinding, iremos aprender como utilizá-lo efetivamente, de maneira prática e fácil.

Até aqui, vimos os conceitos sobre o Databinding, como ele se diferencia do mecanismo de databinding tradicional e entendemos alguns conceitos importantes sobre o mesmo; entendemos como as 4 peças fundamentais no mecanismo de binding se relacionam, a direção do fluxo dos dados e como é desencadeada as atualizações de fonte dentro do mecanismo de binding. Já falamos muito , mão na massa.

Criando o Binding

Recapitulando o nosso aprendizado, temos os quatro componentes que compõem o mecanismo de binding: objeto que será a fonte dos dados (source), o objeto que será o alvo (target), a propriedade de destino (targe property) e a propriedade dentro do objeto fonte que será utilizada como caminho até o valor a ser utilizado (Path). Vejamos o seguinte exemplo para fins de demonstração. Suponhamos que temos um objeto cliente, como uma propriedade string e que desejo utilizá-lo em um textbox, observe abaixo o XAML de exemplo:

img

No pequeno trecho de código XAML acima, vemos os 4 componentes obrigatórios do binding em ação. A classe Pessoa é o objeto fonte de dados (source), o objeto Textbox como objeto de destino (target), a propriedade nome da classe Pessoa como proprieade que contem o valor a ser usado (Path) e por fim a propriedade Text da classe TextBox como propriedade de destino (target property). Para ilustrar melhor olha como ficaria um diagrama do exemplo acima:

img

Perceba que no objeto Texbox, não especificamos o Source, ou seja, isto chama-se Binding por omissão. Por não especificar o source, o objeto Textbox herda o Source do seu objeto Pai, sendo necessário apenas especificar a propriedade Path em que o valor da mesma será utilizado e a propriedade destino no caso a propriedade Text.

Entendendo o Binding Source

Entender como especificar o BindingSource é muito importante, pois sem uma fonte para os dados não seria possível fazer absolutamente nada. O exemplo de código anterior, o DataContext é especificado somente para o objeto Grid, isto quer dizer que todos os objetos filho de Grid herdam o seu DataContext. Existem várias maneiras de se especificar o BindingSource, ou seja, a origem dos dados a serem utilizados. O Binding por omissão é útil, quando queremos ligar vários objetos utilizando propriedades de uma mesma fonte, mais você pode especificar diretamente no objeto de destino o objeto fonte de dados (Binding Source), conforme ilustra a figura abaixo:

img

O objeto fonte de dados, pode ainda ser especificado utilizando-se a propriedade da classe Binding chamada ElementName. Conforme ilustra a figura abaixo, o objeto Textblock está ligado ao objeto Textbox atravéz desta propriedade,fazendo com que tudo que é digitado na caixa de texto apareça no Textblock.

img

A Propriedade Path

Se a sua fonte de dados é um objeto de negócios, você utilizar a propriedade da classe Binding, chamada Path para indicar o valor a ser utilizado pelo Binding.O primeiro exemplo neste artigo ilustra bem isto, em que o objeto de fonte de dados é um objeto de negócios chamado pessoa e a propriedade utilizada pelo Textbox é a propriedade nome.

Dica Importante: Quando é utilizada a ligação vazia, ItemsSource{Binding}, o objeto em questão que utiliza esta declaração, herda o DataContext do objeto Pai, podendo fazer uso de qualquer propriedade do objeto fonte de dados que está ligado ao objeto pai.

ValueConverters

Observe o seguinte exemplo:

img

A propriedade Background da classe Button é do tipo Brush, mais está sendo atribuído um valor do tipo string a ela. Talvez você esteja se perguntando como é que funciona isto? Uma propriedade que é do tipo Brush, estar sendo associado a ela um valor do tipo string e não dar exceção? Não é mágica, isto se deve graças aos TypeConverters, que fazem com que haja uma conversão de um determinado tipo, para o tipo correto da propriedade. Veja o diagrama abaixo:

img

Os TypeConverters podem serem construindo através da implementação da interface IValueConverter. Como o exemplo de código abaixo:


[ValueConversion (typeof (Color), typeof (SolidColorBrush)) ]
public class ColorBrushConverter : IValueConverter
{
public object Convert (object value, Type targetType, object parameter, 
System.Globalization.CultureInfo culture) 
{
Color color = (Color) value;
return new SolidColorBrush (color) ;
}

public object ConvertBack (object value, Type targetType, object parameter, 
System.Globalization.CultureInfo culture) 
{
return null;
}
}

São classes como estas, que permitem a “mágica” mostrada no exemplo funcionar, onde o valor de uma prpriedade do tipo string por exemplo, consiga ser atribuída a uma propriedade cujo valor é do tipo Brush. Bom pessoal, assim terminamos mais uma parte deste assunto muito importante dentro da arquitetura WPF, que é o Binding. Espero que vocês esteja conseguindo acompanhar e atentar para os detalhes do mecanismo de Binding que são extremamente poderosos e úteis na hora de realizar a ligação dos dados em uma aplicação WPF.



Bom pessoal até aqui, vimos criação do binding, fluxo de dados, conversão de dados, os 4 elementos que compõem o mecanismo de binding, enfim já apredemos bastante, mais ainda não acabou. Nesta parte final, iremos aprender sobre binding com coleções, validação e finalizar esta série de artigos que teve por objetivo, passar o entendimento de como o mecanismo de databinding dentro do WPF é diferenciado, como ele pode ser um aliado poderoso na construção de aplicações corporativas.



Efetuando o Binding com Coleções

Até aqui, abordamos cenários em que o binding é feito utilizando como objeto fonte (source) , um objeto único que contém várias propriedades que podem ser utilizadas. Mais existem cenários, em que a necessidade em questão, seja utilizar um conjunto de objetos e não somente um único objeto como fonte de dados; a partir deste conjunto de objetos realizar um filtro, pesquisa ou até mesmo um agrupamento de informações. É justamente em cenários como este, que entra em ação o Binding com coleções. Controles com a propriedade ItemsControl como ListBox, TreeView ou ListView são comumente usados para visualizar estas coleções. Atente para o diagrama abaixo:

img

Note que o diagrama utilizado, é como os que foram utilizados nos artigos anteriores, ou seja, você liga a propriedade ItemsSource (propriedade de destino - target) a uma coleção de objetos como fonte de dados. Note que a ligação é OneWay e a propriedade ItemsSource, suporta binding por omissão. Veja o exemplo abaixo:

img

A classe Tarefa utilizada no exemplo:

img

O code-behind da janela do exemplo:

img

Na primeira figura, vemos destacado em vermelho, a declaração do objeto fonte de dados (source) , através da declaração Source=Tarefas, que é uma propriedade da janela que guarda uma Coleção de objetos do tipo Tarefa; E destacado em azul, a declaração de qual propriedade terá seu valor utilizado. Veja que o binding com coleções é simples, semelhante ao binding para um objeto único, exceto pelo fato de que o objeto fonte de dados, passa a ser um conjunto de objetos e não somente um objeto único.

É possível fazer utilizar e iterar sobre qualquer coleção, que implemente a interface IEnumerable. Uma funcionalidade interessante, é que podemos ser notificados quando um item em uma determinada coleção é adicionado, ou retirado. Para que venhamos receber esta notificação, e a mesma refletir na tela para o usuário, temos que utilizar coleções que implemente a interface INotifyPropertyChanged. O WPF fornece algumas destas coleções como ObservableCollection, BindingList, Collection ou até mesmo a famosa List.

CollectionViews

Como foi dito no inicio do artigo, você pode querer filtrar, classificar agrupar, enfim realizar alguma ação relacionada ao conjunto de objetos que você possui como fonte de dados; Para poder fazer isto você precisa utilizar coleções que implemente a interface IcollectionView e ligá-la a seu ItemControl. CollectionViews, é uma camada sobre a coleção de dados utilizada como fonte de dados, que permite que você realize operações nos objetos da coleção, sem ter que mudar a coleção de origem, ou seja, você pode avegar ou filtrar os objetos e a coleção de origem dos mesmo, não será alterada. A CollectionView, também tem um ponteiro para o item atual da coleção, como mostra a figura abaixo:

img

Um fato interessante, é que por utilizar a collection View não mudar a coleção de destino, você pode ter na mesma tela, um controle que exibe os dados de uma forma, e outro utilizando a mesma coleção exibindo os mesmos dados de outra. Por exemplo você pode ter um DataGrid com todos os funcionários ordenado por nome e um outro DataGrid com os funcionários ordenados por número de venda. Chega de falatório mão na massa.

Uma maneira de utilizar CollectionViews, é istânciar um objeto do tipo CollectionViewSource e utilizá-lo como Source. Observe o exemplo abaixo, o Binding é configurado apontando para o objeto CollectionViewSource, ao invéz de apontar para a coleção diretamente, o exemplo abaixo mostra claramente isto:

img
  1. É instanciado declarativamente um objeto do tipo CollectionViewSource, que será utilizado como source pela ListBox. O Binding é configurado por omissão {Binding}, ou seja, os dados serão obtidos em tempo de execução. E vejam que tem um agrupamento configurado e apontando para a propriedade Nome da Turma.
  2. É declarado um DataTemplate (falaremos mais adiante) , que será utilizado pelos itens da ListBox.
  3. O Binding não está apontando para a coleção diretamente, ao invés disto, ele aponta para o objeto CollectionViewSource de nome colecaoTurmas.
  4. Foi especificado na ListBox, qual template será utilizado para o agrupamento, no caso o template de nome TurmaTemplate.
  5. Está sendo declarado dentro da listbox, um DataTemplate, para cada item da listbox, no caso apontando para uma propriedade, dentro da classe Turma, que é uma coleção de alunos. Sendo configurado ainda que no Textblock a propriedade a ter seu valor utilizado, é a propriedade Nome, da classe aluno.

No caso, se fosse necessário utilizar a mesma coleção, mais com outra visão ou agrupamento, seria necessário apenas declarar outro objeto CollectionViewSource com outro nome, e utilizar em um outro controle, mais apontando para a mesma coleção.

Tipo de Coleção Source Tipo de Collectionview Notas
IEnumerable Um tipo interno baseado em CollectionView Não permite agrupar itens
IList ListCollectionView O mais rápido
IBindingList BindingListCollectionView Ação

Classificação de Coleções

Como foi dito no inicio do artigo, é possivel aplicar uma ordem aos itens da coleção. A CollectionViewSource, permite que seja alterada a ordem em que estejam os itens da coleção, como também, estabelecer uma nova ordem a partir de critérios. Veja o exemplo, que está sendo realizada uma ordenação pela categoria e pela data inicial:


private void AddSorting (object sender, RoutedEventArgs args) 
{
 
 listingDataView.SortDescriptions.Add (
 new SortDescription ("Categoria", ListSortDirection.Ascending)) ;
 listingDataView.SortDescriptions.Add (
 new SortDescription ("DataInicial", ListSortDirection.Ascending)) ;
}

Filtragem

Outro recurso muito útil é a possibilidade de realizar filtros na coleção. E com estas capacidades, você pode ter controles distintos utilizando a mesma coleção, sendo que um controle mostra os dados da coleção de uma forma, sendo que o outro pode mostrar as informações a partir de um filtro feito sobre a mesma. Observe o exemplo abaixo, em que é aplicado um filtro na coleção, em que só serão obtidos os pedidos com valor acima de R$100,00:


listingDataView.Filter += new FilterEventHandler (MostraSomentePedidosValorAcimaCem) ;

Manipulador do evento

private void MostraSomentePedidosValorAcimaCem (object sender, FilterEventArgs e) 
{
 Pedido objPedido = e.Item as Pedido;

 if (objPedido != null) 
 {
 if (objPedido.Valor > 100) 
 {
 e.Accepted = true;
 }
 else
 {
 e.Accepted = false;
 }
 }
}

Agrupamento

O Agrupamento, permite que a CollectionView particionar os itens da coleção em grupos lógicos. Os grupos lógicos podem ser implícitos ou explícitos. Explicito quando o usuário fornece uma lista de grupo e Implícitos quando os grupos são gerados dinamicamente dependendo dos dados. O exemplo abaixo mostra o agrupamento por categoria:


PropertyGroupDescription objGroupDescription = new PropertyGroupDescription () ;
groupDescription.PropertyName = "Categoria";
listingDataView.GroupDescriptions.Add (groupDescription) ;

DataTemplates

DataTemplates são templates, que podem ser aplicados a itens dentro de um controle. Os DataTemplates são muito úteis, quando você deseja que os dados sejam exibidos de alguma forma que não seja a habitual, podendo assim até alterar a aparência, cor de fundo e outras características de um item de uma ListBox por exemplo. Olhe a figura abaixo:

img

Veja que o DataTemplate, está apontando para um tipo Aluno, e que o template contém um stackPanel de orientação horizontal e um TextBlock que irá mostrar o nome do aluno. Este template mostrado acima, será aplicado a cada item que for adicionado ao ListBox, que será preenchido com uma coleção de objetos do tipo Aluno. Os DataTemplates são muito poderosos e úteis, podendo serem configurados de acordo com a necessidade da aplicação. Bom Pessoa, chegamos ao fim desta nossa série sobre o Mecanismo de Binding no WPF. Espero ter ajudado e contribuído de alguma forma para o crescimento profissional de cada leitor.

Confira também