André Alves de Lima

Talking about Software Development and more…

Data Binding no WPF

[Atenção!!! Este artigo tem sua versão em vídeo! Se quiser pular a parte escrita e só assistir o vídeo, dê uma olhada no final do post!]

Falaí pessoal, tudo certo?

No post de hoje vou falar um pouco sobre o Data Binding do WPF, que é uma das funcionalidades mais interessantes do WPF.

Primeiramente, vamos à definição de Data Binding: é o conceito de estabelecer uma conexão entre elementos da User Interface e a sua camada de negócios. Dessa forma, uma vez que os dados são alterados na sua camada de dados, a User Interface é automaticamente atualizada para refletir essas alterações e vice-versa.

No WPF, você pode fazer Data Binding dos controles com propriedades de um objeto, propriedades de outros controles e até mesmo com elementos de um XML. Neste primeiro artigo da série sobre data binding no WPF veremos como ligamos as propriedades de um controle com alguma propriedade de outro controle e também com propriedades de um objeto.

Primeiramente, vejamos os principais elementos do Binding do WPF:

Source: define a fonte de dados que alimentará o binding;
Path: o nome da propriedade da sua fonte de dados que fornecerá o valor para o controle em questão;
XPath: o mesmo que Path, mas, utilizado quando estamos fazendo Binding com XML;
Mode: define a direção do binding (maiores detalhes mais adiante neste artigo);
UpdateSourceTrigger: define quando o binding será disparado (maiores detalhes mais adiante neste artigo);
Converter: define um conversor para os valores do seu binding (maiores detalhes num próximo artigo).

Como disse acima, o elemento Mode define a direção do fluxo de dados do binding, ou seja, quem será atualizado (User Interface ou fonte de dados) quando um valor for alterado. As opções para o elemento Mode são:

TwoWay: sempre que algum valor for alterado na fonte de dados, a interface é atualizada e vice-versa;
OneWay: valores alterados na fonte de dados são refletidos na User Interface, mas, alterações na User Interface não são refletidas na fonte de dados;
OneWayToSource: é o oposto do OneWay, ou seja, quando a User Interface for atualizada, a fonte de dados é atualizada para refletir a alteração, mas, quando a fonte de dados é atualizada as alterações não são refletidas na User Interface;
OneTime: busca os valores na fonte de dados para alimentar a User Interface uma vez que o binding é carregado. Todas as alterações seguintes tanto na fonte de dados quanto na User Interface não serão refletidas pelo binding;
Default: depende da Dependency Property que está sendo utilizada no binding. Para as dependency properties editáveis (por exemplo Text, IsChecked, etc.) o default é o TwoWay e para o restante das propriedades o default é o OneWay.

Já o elemento UpdateSourceTrigger define o momento em que o binding será disparado. As opções para esse elemento são:

PropertyChanged: o binding é disparado sempre que as propriedades ligadas a ele forem atualizadas. É o default para a maioria das dependency properties, exceto para as propriedades Text, cujo UpdateSourceTrigger default é o LostFocus;
LostFocus: o binding é disparado sempre que o controle ligado a ele perder o foco;
Explicit: o binding nunca é disparado, a não ser que você explicitamente chame o método UpdateSource do binding.

Vamos agora a uma demonstração dos conceitos abordados acima. Para isso, vamos criar um projeto do tipo WPF Application utilizando o Visual Studio 2010 e .NET Framework 4.

Nesse novo projeto, vamos incluir alguns controles na nossa MainWindow: um Slider, uma ProgressBar e um TextBox, todos dentro de um StackPanel, como podemos ver no código abaixo:

A ideia nesse exemplo é implementarmos um binding para que, uma vez que o valor do Slider seja alterado, esse valor seja refletido tanto na ProgressBar quanto no TextBox. Para isso, implementamos o binding desta forma:

Ao executarmos esse novo código, percebemos que nossa aplicação se comporta da maneira esperada, ou seja, ao mudarmos o Slider, a ProgressBar e o TextBox são atualizados.

Porém, perceba que se você tentar digitar algum valor no TextBox, os valores no Slider e na ProgressBar não mudam até que o TextBox perca o foco. Isso acontece pois, como falamos anteriormente, o UpdateSourceTrigger default para propriedades Text é o LostFocus. Faça agora um teste para ver a mudança de comportamento ao especificarmos que o UpdateSourceTrigger do binding to TextBox é PropertyChanged:

No nosso segundo exemplo veremos como ligar propriedades de uma classe nos controles da nossa Window. Para isso, vamos incluir uma nova Window no nosso projeto (Window1) e definir o seguinte layout inicial:

Já no code-behind da nossa Window1, vamos criar uma classe que servirá de fonte de dados para o nosso binding:

namespace WpfApplication3
{
    public partial class Window1 : Window
    {
        public Window1()
        {
            InitializeComponent();
        }
    }

    public class Exemplo
    {
        private string propriedade1;
        public string Propriedade1
        {
            get { return propriedade1; }
            set { propriedade1 = value; }
        }

        private int propriedade2;
        public int Propriedade2
        {
            get { return propriedade2; }
            set { propriedade2 = value; }
        }
    }
}

Feito isso, vamos incluir no XAML da declaração da nossa Window1 uma entrada de namespace apontando para o namespace da nossa aplicação. Vamos também adicionar um StaticResource que vai ser uma instância da nossa classe Exemplo e setar o DataContext do nosso Grid como sendo esse StaticResource:

Após essas alterações, podemos adicionar o binding nos nossos TextBoxes apontando para as propriedades do nosso objeto. Isso é feito da seguinte maneira:

Finalmente, para entendermos o quê está acontecendo por trás do binding e verificar se realmente as propriedades e controles estão refletindo os valores corretos, implementemos os handlers para o evento Click dos nossos botões:

E no code-behind:

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

        private void btAlterarObjeto_Click(object sender, RoutedEventArgs e)
        {
            ((Exemplo)meuGrid.DataContext).Propriedade1 = "Valor novo";
            ((Exemplo)meuGrid.DataContext).Propriedade2 = 2011;
        }

        private void btExibirPropriedade_Click(object sender, RoutedEventArgs e)
        {
            MessageBox.Show(string.Format("Propriedade1 = {0}\nPropriedade2 = {1}", ((Exemplo)meuGrid.DataContext).Propriedade1, ((Exemplo)meuGrid.DataContext).Propriedade2));
        }
    }

Agora altere a StartupUri do seu projeto (no App.xaml) para Window1.xaml e execute a aplicação. Digite qualquer valor nos dois TextBoxes e clique no botão “Exibir Propriedade”. Note que os valores estão corretamente armazenados na nossa instância da classe Exemplo.

Porém, ao clicarmos no botão “Alterar Objeto”, percebemos que os valores no TextBox não são alterados, entretanto, conferindo com o botão “Exibir Propriedade”, verificamos que as propriedades na instância da classe Exemplo foram realmente alterados no background. Isso acontece porque da maneira que implementamos a classe Exemplo, o WPF não está sendo notificado das alterações ocorridas nas propriedades e, por isso, a interface não é atualizada.

Para corrigirmos isso devemos fazer com que a nossa classe Exemplo implemente a propriedade INotifyPropertyChanged, do namespace System.ComponentModel. Fazemos isso da seguinte maneira (não esqueça de incluir um using para o namespace System.ComponentModel):

    public class Exemplo : INotifyPropertyChanged
    {
        private string propriedade1;
        public string Propriedade1
        {
            get { return propriedade1; }
            set
            {
                propriedade1 = value;
                if (PropertyChanged != null)
                    PropertyChanged(this, new PropertyChangedEventArgs("Propriedade1"));
            }
        }

        private int propriedade2;
        public int Propriedade2
        {
            get { return propriedade2; }
            set
            {
                propriedade2 = value;
                if (PropertyChanged != null)
                    PropertyChanged(this, new PropertyChangedEventArgs("Propriedade2"));
            }
        }

        #region INotifyPropertyChanged Members
        public event PropertyChangedEventHandler PropertyChanged;
        #endregion
    }

Pronto! Feito isso nossa aplicação se comporta da maneira esperada!

E aqui acaba o artigo introdutório sobre o Binding do WPF. Nos próximos artigos confira maiores detalhes dessa poderosa feature do WPF.

Para conferir a versão em vídeo desse artigo, assista no MSDN a partir deste link.

Até a próxima!

André Alves de Lima.

12 thoughts on “Data Binding no WPF

  • […] ATENÇÃO!!! ESTE BLOG MUDOU DE ENDEREÇO: http://www.andrealveslima.com.br VISITE ESTE MESMO POST NO NOVO ENDEREÇO AQUI […]

  • Data Binding no WPF | Raptors disse:

    […] LINK PARA O POST ORIGINAL AQUI! […]

  • Vagner disse:

    Excelente artigo!
    Só tenho uma dúvida. Como eu faço pra pegar os valores das propriedades da própria classe “Window1″, no seu exemplo?

    • andrealveslima disse:

      Vagner,
      Primeiramente obrigado pelo comentário!
      Para fazer um binding utilizando uma propriedade da sua própria Window você precisa utilizar o conceito de RelativeSource… Vamos supor que você tenha uma propriedade na sua Window chamada “SuaPropriedade”… Um binding apontando para essa propriedade seria assim:

      (tirando o menor e maior senao ele nao deixa postar no comentário):

      TextBox Text=”{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type Window}}, Path=SuaPropriedade}”

      []’s,

      André Alves de Lima.

  • Samuel Diogo disse:

    Olá André, descobri seu site por acaso ao conferir seu perfil do msnd, e estou muito contente com o que li, na verdade eu estou me aperfeicoando na programação de três camadas e sempre a camada UI fiz no WindowsForms, só que nos ultimos dias eu recebi uma proposta de desenvolver um pequeno sistema de controle financeiro com os menus no estilo do office 2010, e mesmo sabendo que é possível fazer no forms, eu optei pelo desavio do WPF porém não estava entendendo bem o funcionamento do DataBinding até ver este post que realmente abriu minha mente e pude entender como esta “engenhoca” funciona! rsrs Agora vou tentar aplicar no meu projeto!
    Obrigado por compartilhar seu conhecimento!
    Sds,
    Sam

    • andrealveslima disse:

      Samuel,
      Muito obrigado pelo seu comentário! Comentários desse tipo que me motivam a continuar contribuindo com a comunidade!
      Grande abraço!
      André Alves de Lima

  • Danielle disse:

    Boa Noite André,

    Parabéns pelo artigo. Gostei tanto que até estou estudando a guia de certificação 70-511 no msdn.

    Obrigada por compartilhar o seu conhecimento!!!!

  • kauelira disse:

    Muitoooo Bom! Ajudou *–*

  • Roberth disse:

    Olá, muito bacana seu artigo… mas eu tenho uma dúvida: Vamos imaginar que eu tenho 3 textbox, onde 2 receberão valores numericos com casas decimais e o terceiro deve ter a soma dos valores dos 2 textbox anteriores… Há como fazer isso?

    ex:

    <textbox x:name="total" text="” />

    • andrealveslima disse:

      Olá Roberth, obrigado pelo comentário!

      Você está bindando os TextBoxes com alguma propriedade na sua ViewModel, ou esses valores só estão disponíveis diretamente nos TextBoxes? Como é que está exatamente o seu XAML e a sua ViewModel?

      Se você estiver trabalhando com ViewModel, acho que o mais indicado seria criar uma propriedade readonly que faz o somatório e aí bindar essa propriedade no terceiro TextBox..

      Abraço!
      André Lima

    • andrealveslima disse:

      Olá novamente, Roberth! Conseguiu dar uma olhada na minha resposta? Ainda está com essa dificuldade ou conseguiu resolver?

      Abraço!
      André Lima

Deixe uma resposta

O seu endereço de e-mail não será publicado. Campos obrigatórios são marcados com *