TOC

This article has been localized into Ukrainian by the community.

Прив'язка даних:

Відповідь на зміни

Раніше ми, зазвичай, створювали прив'язки між UI об'єктами та існуючими класами., але в справжніх застосунках ви, вочевидь, здіюснюватимете прив'язку до ваших власних об'єктів даних. Це дуже просто, однак є одна проблема: зміни не відображаються автоматично, як це було в попередніх прикладах. Тож в наступному прикладі ви дізнаєтесь, як це зробити:

Відображення змін в джерелах даних

Є всього два основні сценарії внесення змін до джерел даних: зміни в списку об'єктів та зміни зв'язаних властивостей об'єктів даних. Робота з ними в значній мірі залежить від того, що ви хочете зробити, однак WPF пропонує два прості рішення, які підійдуть для більшості випадків: інтерфейси ObservableCollection та INotifyPropertyChanged.

Наступний приклад покаже навіщо вони потрібні:

<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; }
	}
}

Якщо ви запустите цей приклад, то додавши щось до списку чи змінивши ім'я одного з користувачів, побачите, що в UI нічого не оновлюється. Цей простий приклад містить клас User, який своєю чергою містить ім'я користувача, ListBox, що показує ці імена, та кнопки для роботи зі списком та його вмістом. ItemsSource списку - це короткий список з пари користувачів, створений в конструкторі вікна. Проблема в тому, що жодна із кнопок не працює. Давайте виправимо її за два короткі кроки.

Відображення змін у джерелі даних списку

Перший крок - змусити UI відповідати на зміни в джерелі списку (ItemsSource), коли ми додаємо чи видаляємо користувача. Нам потрібен список, що повідомляє про будь-які зміни свого вмісту. WPF містить тип списку, що виконує це завдання. ВІн називається ObservableCollection, його можна використовувати так само, як і звичайний List<T>, але з кількома особливостями.

В останньому прикладі, що знаходиться нижче ми просто замінили List<User> на ObservableCollection<User>. Завдяки цьому кнопки "Додати" та "Видалити" будуть працювати. Але цього не достатньо для того, щоб увімкнути кнопку "Змінити ім'я". Оскільки зміни відбудуться в самому об'єкті, а не в списку. Наступний крок допоможе вирішити цю проблему.

Відображення змін в об'єктах даних

Другий крок полягає в тому, щоб клас User успадковувався від інтерфейсу INotifyPropertyChanged. Завдяки цьому екземпляри класу User зможуть повідомити UI про зміну своїх властивостей. Це куди складніше ніж змінити тип списку. Однак це все ж один з найпростіших способів реалізувати автоматичне оновлення.

Фінальний, робочий приклад

Тепер, після проходження цих кроків ми створили приклад, у якому всі зміни даних автоматично відображаються:

<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));
		}
	}
}

Підсумок

Як ви бачите,INotifyPropertyChanged дуже просто успадковувати. Треба лише додати трохи додаткового коду до вашого класу та трохи додаткової логіки до ваших властивостей. Це ціна, яку доведеться заплатити, щоб негайно відображати зміни в інтерфейсі користувача при прив'язці даних. Вочевидь вам потрібно лише викликати NotifyPropertyChanged у налаштуваннях властивостей, до яких ви прив’язуєтеся - решта може залишитися без змін.

З іншого боку, з ObservableCollection дуже легко працювати. Потрібно лише використовувати цей тип списку у випадках, де вам треба автоматично відображати зміни в списку.


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!