TOC

This article is currently in the process of being translated into Korean (~96% done).

데이터 바인딩:

Responding to changes

지금까지 이 튜토리얼에서는 대부분 UI 요소와 기존 클래스 간의 바인딩을 만들었지 만 실제 응용 프로그램에서는 분명히 자신의 데이터 객체에 바인딩 할 것입니다. 이것은 쉬운 일이지만 일단 시작하면 실망스러운 것을 발견 할 수 있습니다. 이전 예에서와 같이 변경 사항이 자동으로 반영되지 않습니다. 이 글에서 배우겠지만,이 작업을 수행하려면 약간의 추가 작업이 필요하지만 다행히도 WPF를 사용하면 이 작업이 매우 쉽습니다.

Responding to data source changes

데이터 소스 변경을 다룰때 처리 할 수도 있고 처리하지 않을 수도있는 두 가지 시나리오가 있습니다. 항목 목록 변경 및 각 데이터 객체의 바인딩 된 속성 변경. 처리 방법은 수행하는 작업과 수행하려는 작업에 따라 다를 수 있지만 WPF에는 사용할 수있는 매우 쉬운 두 가지 솔루션인 ObservableCollectionINotifyPropertyChanged 인터페이스가 제공됩니다.

다음은 예제는 왜 이 두가지가 필요한지 보여줍니다 :

<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는 Window 생성자에서 만든 두 명의 사용자의 퀵리스트에 할당됩니다. 그러나 문제가 있는데 해당 예제에서는 버튼이 작동하지 않는 것 같습니다. 두가지의 간단한 단계를 통해 문제를 해결해 봅시다.

데이터 소스 리스트의 변경사항 반영하기

첫 번째 단계는 사용자를 추가하거나 삭제할 때와 같이 소스 리스트(ItemsSource)의 변경 사항에 UI가 응답하도록하는 것입니다. 우리에게 필요한 것은 콘텐츠의 변경 사항을 대상에 알리는 리스트이며 다행히 WPF는 이를 수행하는 리스트 유형을 제공합니다. 이것을 ObservableCollection이라고 합니다. 이것은 일반적인 List<T>와 매우 유사하지만 몇 가지 차이점이 있습니다.

아래의 마지막 예제에서는 List<User>를 ObservableCollection<User>로 간단히 교체했습니다. 이것이 당신이 해야 할 전부입니다! 이렇게하면 Add 및 Delete 버튼이 작동하지만 "Change name" 버튼을 클릭 시 아무일도 일어나지 않습니다. 왜냐하면 변경사항이 바인딩된 데이터 객체 자체에서 일어나는 일이며 소스 리스트에서는 일어나지 않았기 때문입니다. 두번째 단계로 해당 내용을 다뤄 봅시다.

데이터 객체의 변경사항 반영하기

두 번째 단계는 사용자 지정 User 클래스가 INotifyPropertyChanged 인터페이스를 구현하도록하는 것입니다. 이를 통해 사용자 개체는 UI 레이어에 속성 변경 사항을 알릴 수 있습니다. 이것은 위에서했던 것처럼 리스트 유형을 변경하는 것보다 약간 더 번거롭지만, 자동적으로 업데이트를 하기 위한 가장 간단한 방법 중 하나입니다.

정상 작동 하는 예제와 마무리

위에서 설명한 2가지 변경 사항을 참고하여, 아래와 같이 데이터 소스가 반영되는 예제를 만들 수 있습니다.

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

Summary

살펴본 것과 같이 INotifyPropertyChanged를 구현하는 것은 매우 쉽지만 클래스에 약간의 추가 코드를 만들고 프로퍼티에 약간의 추가적인 논리를 추가해야합니다. 이것은 자신의 클래스에 바인딩하고 변경 사항이 UI에 즉시 반영되도록하기 위해서 해야만 하는 것들입니다. 당신이 바인딩한 프로퍼티의 setter에서 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!