WPF - Usando databinding com um DataTemplate


Um DataTemplate é um recurso do WPF que permite uma grande flexibilidade para definir a apresentação de dados vinculados, dessa forma os Data templates permitem customizar a aparência de um controle.

A classe DataTemplate descreve a estrutura visual de um objeto de dados e você usa este recurso para especificar a visualização dos seus dados.

Neste artigo veremos como usar databinding com um DataTemplate para exibir informações em uma aplicação WPF: Vou exibir uma lista de grupos de bandas de rock dos anos 60/70 com nomes e imagens.

A vinculação de objetos a elementos de interface (GUI) no WPF é implementada da mesma forma que em aplicações Windows Forms : temos classes com propriedades que são lidas em tempo de execução e exibidas nos controles.

Então o que há de novo no WPF ?

A diferença para aplicações WinForms reside no fato de que a camada de interface com o usuário (GUI) não é especificada no código mas definida no descritor usando a linguagem XAML e um dos recursos existentes é usar um DataTemplate para definir o leiaute do controle que desejamos exibir.

Vejamos então o exemplo onde iremos exibir uma lista de grupos de rock com nome e imagens.

Abra o Visual Studio 2010 Express Edition e crie uma aplicação do tipo WPF Application. Selecione no menu File->New Project e a seguir selecione Other Languages -> Visual C# -> Windows e o template WPF Application com o nome dataTemplateLista e clique em OK;

No nosso exemplo teremos uma lista de objetos que será vinculado a um ItemsControl da WPF.

Um ItemsControl é um tipo de controle que pode conter vários itens, tais como strings, objetos ou outros elementos.

A primeira coisa a fazer é definir uma classe chamada Pessoa.cs com os campos Nome e ImagemRef pois iremos exibir o nome e a imagem da banda.

Clique com o botão direito do mouse sobre o nome do projeto e selecione Add Class informando o nome Pessoa.cs.

A seguir defina o seguinte código na classe:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace dataTemplateLista
{
    public class Pessoa
    {
        public static Pessoa Criar(string nome,string imagemRef)
        {
            Pessoa pessoa = new Pessoa();
            pessoa.Nome = nome;
            pessoa.ImagemRef = imagemRef;

            return pessoa;
        }

        private string _nome;
        public string Nome
        {
            get { return _nome; }
            set { _nome = value; }
        }

        private string _imagemRef;
        public string ImagemRef
        {
            get { return _imagemRef; }
            set { _imagemRef = value; }
        }
    }
}

Vamos criar agora uma pasta chamada Imagens onde iremos armazenar as fotos das bandas que iremos exibir. Clique com o botão direito do mouse sobre o nome do projeto e selecione Add -> New Folder e informe o nome Imagens. A seguir copiamos as imagens na pasta do projeto.

A figura ao lado vemos a janela Solution Explorer exibindo a estrutura do projeto

onde vemos a pasta Imagens contendo as imagens das bandas e a classe Pessoa.cs.

A seguir vamos definir o leiaute da interface no arquivo MainWindow.xaml conforme abaixo:

O código XAML para este leiaute é dado a seguir:

<Window x:Class="dataTemplateLista.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="300">
        <Window.Background>
            <LinearGradientBrush StartPoint="0,0" EndPoint="0,1">
                <GradientStop Color="LemonChiffon" Offset="0"/>
                <GradientStop Color="Yellow" Offset="1"/>
            </LinearGradientBrush>
        </Window.Background>
    <Grid>
        <ListBox Name="pessoaItems" Margin="10" Background="LightBlue">
            <ListBox.ItemTemplate>
                <DataTemplate>
                    <Grid Margin="3" Width="200" Background="White">
                        <TextBlock Foreground="Blue"
                             FontWeight="Bold"
                             Text="{Binding Path=Nome}"
                             TextWrapping="Wrap"
                             VerticalAlignment="Center"/>
                        <Image
                         Width="50" Height="50"
                         HorizontalAlignment="Right"
                         Source="{Binding Path=ImagemRef}"/>
                    </Grid>
                </DataTemplate>
            </ListBox.ItemTemplate>
        </ListBox>
    </Grid>
</Window>

Neste código estamos definindo um gradiente de cores no formulário:

<Window.Background>
    <LinearGradientBrush StartPoint="0,0" EndPoint="0,1">
    <GradientStop Color="LemonChiffon" Offset="0"/>
    <GradientStop Color="Yellow" Offset="1"/>
    </LinearGradientBrush>
</Window.Background>

e no interior do Grid temos a definição do nosso DataTemplate para o controle ListBox:

Obs: Os DataTemplates permite personalizar a aparência de um controle, configurando-o conforme queremos que ele seja exibido.

   <ListBox Name="pessoaItems" Margin="10" Background="LightBlue">
            <ListBox.ItemTemplate>
                <DataTemplate>
                    <Grid Margin="3" Width="200" Background="White">
                        <TextBlock Foreground="Blue"
                             FontWeight="Bold"
                             Text="{Binding Path=Nome}"
                             TextWrapping="Wrap"
                             VerticalAlignment="Center"/>
                        <Image
                         Width="50" Height="50"
                         HorizontalAlignment="Right"
                         Source="{Binding Path=ImagemRef}"/>
                    </Grid>
                </DataTemplate>
            </ListBox.ItemTemplate>
        </ListBox>

onde temos a definição do databinding para o Nome (Text="{Binding Path=Nome}") no controle TextBlock e para ImagemRef ( Source="{Binding Path=ImagemRef}") no controle Image.

A classe Binding esta no namespace System.Windows.Data e é responsável por manter a comunicação entre a origem e o destino, expondo uma série de propriedades que nos permite
customizar o comportamento dessa comunicação. Entre as principais propriedades, temos:
  • ElementName: define o nome do elemento que servirá como fonte. Utilize esta propriedade quando desejar preencher uma outra propriedade com o valor de um controle do WPF.
  • Mode: determina a direção das informações.
  • NotifyOnSourceUpdated: valor boleano indicando se o evento SourceUpdated é disparado quando alguma atualização na fonte das informações ocorrer.
  • NotifyOnTargetUpdated: valor boleano indicando se o evento SourceUpdated é disparado quando alguma atualização no destino das informações ocorrer.
  • Path: espefica o nome da propriedade que será exibida.
  • RelativeSource: especifica uma fonte de forma relativa à posição do objeto atual.
  • Source: define o nome do objeto que servirá como fonte. Utilize esta propriedade quando desejar preencher com uma instância de um objeto.
  • XPath: a mesma finalidade da propriedade Path, mas define uma expressão XPath quando a fonte de informações for um arquivo Xml.

Finalmente vamos definir o código no arquivo MainWindow.xaml.cs onde na carga da janela chamamos a rotina CriaPessoas() que retorna uma lista de pessoas contendo o nome a imagem da banda que é atribuída a propriedade ItemsSource do controle pessoaItems que é o nosso controle ListBox:

namespace dataTemplateLista
{
     public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
            // vincula a lista de ao ItemsControl
            pessoaItems.ItemsSource = CriaPessoas();
        }
        /// <summary>
        /// Cria um modelo de dados
        /// </summary>
        /// <returns>List<Pessoa></returns>
        private System.Collections.IEnumerable CriaPessoas()
        {
            List<Pessoa> pessoas = new List<Pessoa>();
            pessoas.Add(Pessoa.Criar("Beatles", "/Imagens/Beatles.jpg"));
            pessoas.Add(Pessoa.Criar("Rolling Stones", "/Imagens/RollingStones.jpg"));
            pessoas.Add(Pessoa.Criar("Led Zeppelin", "/Imagens/LedZeppelin.jpg"));
            pessoas.Add(Pessoa.Criar("Black Sabbath", "/Imagens/BlackSabbath.jpg"));
            pessoas.Add(Pessoa.Criar("Pink Floyd", "/Imagens/PinkFloyd.jpg"));
            pessoas.Add(Pessoa.Criar("Jimmi Hendrix", "/Imagens/JimmiHendrix.jpg"));
            pessoas.Add(Pessoa.Criar("Janis Joplin", "/Imagens/JanisJoplin.jpg"));
            return pessoas;
        }
    }
}

Executando o projeto iremos obter o controle ListBox exibindo o nome e a imagem conforme definidos no DataTemplate:

Pegue o projeto completo aqui: datatemplatelista.zip

Eu sei é apenas WPF , mas eu gosto...

Referências:

WPF - Apresentando o DataBinding

WPF - Usando a vinculação de dados : conceitos e prática II

.NET - Introdução ao XAML

WPF - Gerenciando o Layout

WPF - DataBinding com EDM - Usando o Entity Data Model para realizar o databinding no WPF

WPF - Manutenção de dados com DataGrid e LINQ to SQL

WPF - Usando o Componente DataGrid


José Carlos Macoratti