TOC

This article has been localized into Portuguese by the community.

Data binding:

Respondendo a mudanças

Até agora, neste tutorial, criamos principalmente ligações entre elementos da interface do usuário e classes existentes, mas, em aplicações da vida real, você obviamente estará vinculado a seus próprios objetos de dados. Isso é igualmente fácil, mas, depois de começar, você pode descobrir algo que o desaponta: as alterações não são refletidas automaticamente, como nos exemplos anteriores. Como você aprenderá neste artigo, você precisa apenas de um pouco de trabalho extra para que isso aconteça, mas, felizmente, o WPF torna isso muito fácil.

Respondendo a mudanças na fonte de dados

Existem dois cenários diferentes em que você pode ou não querer manipular ao lidar com alterações de fonte de dados: Alterações na lista de itens e alterações nas propriedades associadas em cada um dos objetos de dados. O modo de lidar com eles pode variar, dependendo do que você está fazendo e do que está procurando realizar, mas o WPF vem com duas soluções muito fáceis que você pode usar: o ObservableCollection e a interface INotifyPropertyChanged.

O exemplo a seguir mostrará por que precisamos dessas duas coisas:

<Window x:Class="WpfTutorialSamples.DataBinding.ChangeNotificationSample"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="ChangeNotificationSample" Height="150" Width="300">
	<DockPanel Margin="10">
		<StackPanel DockPanel.Dock="Right" Margin="10,0,0,0">
			<Button Name="btnAddUser" Click="btnAddUser_Click">Add user</Button>
			<Button Name="btnChangeUser" Click="btnChangeUser_Click" Margin="0,5">Change user</Button>
			<Button Name="btnDeleteUser" Click="btnDeleteUser_Click">Delete user</Button>
		</StackPanel>
		<ListBox Name="lbUsers" DisplayMemberPath="Name"></ListBox>
	</DockPanel>
</Window>
using System;
using System.Collections.Generic;
using System.Windows;

namespace WpfTutorialSamples.DataBinding
{
	public partial class ChangeNotificationSample : Window
	{
		private List<User> users = new List<User>();

		public ChangeNotificationSample()
		{
			InitializeComponent();

			users.Add(new User() { Name = "John Doe" });
			users.Add(new User() { Name = "Jane Doe" });

			lbUsers.ItemsSource = users;
		}

		private void btnAddUser_Click(object sender, RoutedEventArgs e)
		{
			users.Add(new User() { Name = "New user" });
		}

		private void btnChangeUser_Click(object sender, RoutedEventArgs e)
		{
			if(lbUsers.SelectedItem != null)
				(lbUsers.SelectedItem as User).Name = "Random Name";
		}

		private void btnDeleteUser_Click(object sender, RoutedEventArgs e)
		{
			if(lbUsers.SelectedItem != null)
				users.Remove(lbUsers.SelectedItem as User);
		}
	}

	public class User
	{
		public string Name { get; set; }
	}
}

Tente executá-lo por conta própria e observe como, mesmo que você adicione algo à lista ou altere o nome de um dos usuários, nada na interface do usuário será atualizado . O exemplo é bastante simples, com uma classe User que manterá o nome do usuário, um ListBox para mostrá-los e alguns botões para manipular a lista e seu conteúdo. O ItemsSource da lista é atribuído a uma lista rápida de alguns usuários que criamos no construtor da janela. O problema é que nenhum dos botões parece funcionar. Vamos consertar isso em dois passos fáceis.

Refletindo alterações na fonte de dados da lista

O primeiro passo é fazer com que a interface do usuário responda às alterações na origem da lista (ItemsSource), como quando adicionamos ou excluímos um usuário. O que precisamos é de uma lista que notifique quaisquer destinos de alterações em seu conteúdo e, felizmente, o WPF fornece um tipo de lista que fará exatamente isso. Chama-se ObservableCollection e você o usa de maneira muito parecida com uma List normal, com poucas diferenças.

No último exemplo, que você encontrará abaixo, nós simplesmente substituímos a List<User> com um ObservableCollection<User> - é tudo que é preciso! Isso fará com que o botão Adicionar e Excluir funcione, mas não fará nada pelo botão "Alterar nome", porque a alteração ocorrerá no próprio objeto de dados vinculados e não na lista de fontes - a segunda etapa tratará desse cenário .

Refletindo mudanças nos objetos de dados

A segunda etapa é permitir que nossa classe de usuário personalizada implemente a interface INotifyPropertyChanged. Ao fazer isso, nossos objetos User são capazes de alertar a camada da interface do usuário de alterações em suas propriedades. Isso é um pouco mais complicado do que apenas mudar o tipo de lista, como fizemos acima, mas ainda é uma das maneiras mais simples de realizar essas atualizações automáticas.

O exemplo final e funcional

Com as duas alterações descritas acima, agora temos um exemplo que refletirá as alterações na fonte de dados. Se parece com isso:

<Window x:Class="WpfTutorialSamples.DataBinding.ChangeNotificationSample"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="ChangeNotificationSample" Height="135" Width="300">
	<DockPanel Margin="10">
		<StackPanel DockPanel.Dock="Right" Margin="10,0,0,0">
			<Button Name="btnAddUser" Click="btnAddUser_Click">Add user</Button>
			<Button Name="btnChangeUser" Click="btnChangeUser_Click" Margin="0,5">Change user</Button>
			<Button Name="btnDeleteUser" Click="btnDeleteUser_Click">Delete user</Button>
		</StackPanel>
		<ListBox Name="lbUsers" DisplayMemberPath="Name"></ListBox>
	</DockPanel>
</Window>
using System;
using System.Collections.Generic;
using System.Windows;
using System.ComponentModel;
using System.Collections.ObjectModel;

namespace WpfTutorialSamples.DataBinding
{
	public partial class ChangeNotificationSample : Window
	{
		private ObservableCollection<User> users = new ObservableCollection<User>();

		public ChangeNotificationSample()
		{
			InitializeComponent();

			users.Add(new User() { Name = "John Doe" });
			users.Add(new User() { Name = "Jane Doe" });

			lbUsers.ItemsSource = users;
		}

		private void btnAddUser_Click(object sender, RoutedEventArgs e)
		{
			users.Add(new User() { Name = "New user" });
		}

		private void btnChangeUser_Click(object sender, RoutedEventArgs e)
		{
			if(lbUsers.SelectedItem != null)
				(lbUsers.SelectedItem as User).Name = "Random Name";
		}

		private void btnDeleteUser_Click(object sender, RoutedEventArgs e)
		{
			if(lbUsers.SelectedItem != null)
				users.Remove(lbUsers.SelectedItem as User);
		}
	}

	public class User : INotifyPropertyChanged
	{
		private string name;
		public string Name {
			get { return this.name; }
			set
			{
				if(this.name != value)
				{
					this.name = value;
					this.NotifyPropertyChanged("Name");
				}
			}
		}

		public event PropertyChangedEventHandler PropertyChanged;

		public void NotifyPropertyChanged(string propName)
		{
			if(this.PropertyChanged != null)
				this.PropertyChanged(this, new PropertyChangedEventArgs(propName));
		}
	}
}

Resumo

Como você pode ver, implementar o INotifyPropertyChanged é bem fácil, mas cria um pouco de código extra nas suas classes e adiciona um pouco de lógica extra às suas propriedades. Este é o preço que você terá que pagar se quiser vincular suas próprias classes e ter as alterações refletidas na interface do usuário imediatamente. Obviamente, você só precisa chamar NotifyPropertyChanged nas propriedades de vinculação do setter - o restante pode permanecer como está.

O ObservableCollection, por outro lado, é muito fácil de lidar - ele simplesmente requer que você use esse tipo específico de lista nas situações em que você deseja que as mudanças na lista de fontes sejam refletidas em um destino obrigatório.


This article has been fully translated into the following languages: Is your preferred language not on the list? Click here to help us translate this article into your language!