WPF데이터바인딩교육, InotifyPropertyChanged 인터페이스, PropertyChanged 이벤트를 통한 데이터 바인딩, WPF학원
http://ojc.asia/bbs/board.php?bo_table=WPF&wr_id=171
ojc.asia
https://www.youtube.com/watch?v=wgz3OyVqfY4&list=PLxU-iZCqT52Cmj47aKB1T-SxI33YL7rYS&index=13&t=1s

https://www.youtube.com/watch?v=Orwyaq51MXQ&list=PLxU-iZCqT52Cmj47aKB1T-SxI33YL7rYS&index=14&t=2s

- 의존 프로퍼티를 정의하는 것은 데이터 바인딩의 소스로서 역할을 수행하는데 이 방법이 유일한 방법은 아니다. 전통적인 방법은 이벤트를 만드는 것인데 이벤트를 특정한 방법으로 정의하면 WPF내의 데이터 바인딩 로직이 이벤트를 사용할 수 있다.
- INotifyPropertyChanged 인터페이스는 속성 값이 변경되면 클라이언트에 알리는 데 사용된다. INotifyPropertyChanged 인터페이스에는 PropertyChanged라는 이벤트가 포함되어 있는데 ViewModel / Model 개체의 속성이 변경되면 PropertyChanged 이벤트를 발생시켜 WPF 바인딩 시스템에 새 값을 알려준다.
- WPF의 데이터 바인딩 로직은 이벤트가 INotifyPropertyChanged 인터페이스를 구현한 클래스안에 정의되어 있으면 이벤트를 찾는다. 이 인터페이스를 상속받아 구현하면 PropertyChangedEventHandler 델리게이트를 기본으로 하는 PropertyChanged 이벤트를 정의해야 한다.
public event PropertyChangedEventHandler PropertyChanged;
- DateTime 프로퍼티를 아래와 같이 수정하자.
public string DateTime
{
get { return DateTime.Now; }
}
- TimerOnTick 메소드를 수정하자.
void TimerOnTick(object sender, EventArgs args) {
if (PropertyChanged != null) {
PropertyChanged(this, new PropertyChangedEventArgs("DateTime"));
}
}
- PropertyChanged 이벤트를 발생시킬 때의 처음인자는 this이며 두번째 인자는 PropertyChangedEventArgs 타입의 객체이다. PropertyChangedEventArgs는 EventArgs를 상속받아 추가적인 string 타입의 PropertyName 이라는 프로퍼티를 정의하는데 이 프로퍼티는 변경될 프로퍼티를 구별하기 위해 사용한다. 또한 PropertyChangedEventArgs는 string 인자를 가진 생성자를 통해 PropertyName을 설정한다.
- 클래스에서 DateTime 이라는 프로퍼티를 정의했다면 DateTime이 변경될 때 PropertyChanged 이벤트가 발생되어야 하는데 아래 코드를 통해 가능하다.
PropertyChanged(this, new PropertyChangedEventArgs(“DateTime”));
- 이 방법이 다수의 프로퍼티를 다루는 좋은 방법이다. 하나의 PropertyChanged 이벤트가 이들을 다 처리하기 때문이다. 아래는 전체 소스코드이니 ClockTicker2.cs를 만들고 MainWindow.xaml를 수정해서 확인해 보자.
- ColckTicker2.cs
using System;
using System.Windows;
using System.Windows.Threading;
using System.ComponentModel;
namespace DigitalClock
{
public class ClockTicker2 : INotifyPropertyChanged
{
// INotyfyPropertyChanged 인터페이스가 요구하는 이벤트
public event PropertyChangedEventHandler PropertyChanged;
// public 프로퍼티, CLR Property
public string DateTime
{
get { return DateTime.Now.ToString(“yyyyMMddHHmmss”); }
}
// 생성자에서 Timer를 설정
public ClockTicker2()
{
DispatcherTimer timer = new DispatcherTimer();
timer.Tick += TimerOnTick;
timer.Interval = TimeSpan.FromSeconds(1);
timer.Start();
}
// PropertyChanged 이벤트를 발생시키는 타이버 이벤트 핸들러
void TimerOnTick(object sender, EventArgs args)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs("DateTime"));
}
}
}
}
InotifyPropertyChanged 인터페이스, PropertyChanged 이벤트를
이용한 데이터 바인딩
- 데이터바인딩에서 소스 객체는 UI 컨트롤 일수도 있지만 위 그림처럼 소스 객체가 C#의 일반 클래스가 될 수도 있는데 이 경우 프로퍼티(속성)의 값이 변경되는 경우 이를 타겟 객체에 알릴 수 있는 메커니즘이 필요 합니다.
- WPF 데이터 바인딩은 이벤트가 INotifyPropertyChanged 인터페이스를 구현한 클래스안에 정의되어 있으면 이벤트를 찾는데 소스 객체의 속성값의 변경을 통지하기 위해서는 이 인터페이스를 상속받아 구현하고 PropertyChangedEventHandler 델리게이트를 기본으로 하는 PropertyChanged 이벤트를 정의해야 합니다.
- PropertyChanged 이벤트를 발생시킬 때의 처음 인자는 this이며 두번째 인자는 PropertyChangedEventArgs 타입의 객체 입니다. PropertyChangedEventArgs는 string 타입의 PropertyName 이라는 프로퍼티가 정의되어 있는데 프로퍼티를 구별하기 위해 사용합니다. 그래서 PropertyChangedEventArgs를 new 하면서 프로퍼티 이름을 넣어 줍니다.
- CallerMemberName특성(Attribute)을 통해 어느 프로퍼티(속성)에서 PropertyChanged 이벤트가 발생했는지 확인 가능 합니다. 만약 CallerMemberName 특성(Attribute)이 없으면 프로퍼티(속성) 이름을 문자열로 지정해야 합니다.
public void RaisePropertyChange([CallerMemberName] string propertyname = null) {
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyname));
}
// PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyname));
}
- 이 방법이 다수의 프로퍼티를 다루는 좋은 방법 입니다. 하나의 PropertyChanged 이벤트가 모든 프로퍼티(속성)에 대한 변경을 처리할 수 있기 때문 입니다.
[INotifyPropertyChanged 인터페이스를 이용한 데이터 바인딩 실습]
프로젝명 : WpfApp8
실습개요
- User 모델을 상속받은 ViewModel 객체가 데이터바인딩의 소스 객체가 되고 이것이 UI쪽 TextBox컨트롤과 데이터바인딩이 이루어 지는데 최초 ViewModel에서 LastName, FirstName을
- KIM, KIL_DONG으로 셋팅하고 이 값이 UI쪽 컨트롤에 표시됩니다. “이름변경” 버튼을 클릭하면 ViewModel에서 LastName, FirstName을 홍길동으로 변경하는데 이것이 UI쪽 컨트롤에 데이터바인딩 되어 UI TextBox 컨트롤에 표시됩니다.
[MainWindow.xaml]
<Window x:Class="WpfApp8.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:WpfApp8"
mc:Ignorable="d"
Title="MainWindow" Height="178.916" Width="556.024">
<Grid HorizontalAlignment="Left" Height="150" VerticalAlignment="Top" Width="546" Margin="0,0,0,-0.4">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="205*"/>
<ColumnDefinition Width="341*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
<Label x:Name="label" Content="First Name" HorizontalAlignment="Left" Margin="34,10,0,0" VerticalAlignment="Top" Height="26" Width="98"/>
<Label x:Name="label1" Content="Last Name" HorizontalAlignment="Left" Margin="34,14.4,0,0" Grid.Row="1" VerticalAlignment="Top" Height="26" Width="98"/>
<TextBox x:Name="textBox" Grid.Column="1" HorizontalAlignment="Left" Height="23" Margin="21.2,10,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="283" Text="{Binding FirstName}"/>
<TextBox x:Name="textBox1" Grid.Column="1" HorizontalAlignment="Left" Height="23" Margin="21.2,14.4,0,0" Grid.Row="1" TextWrapping="Wrap" VerticalAlignment="Top" Width="283" Text="{Binding LastName}"/>
<Button x:Name="button" Content="보기" Grid.Column="1" HorizontalAlignment="Left" Margin="21.2,10,0,0" Grid.Row="2" VerticalAlignment="Top" Width="127" Height="30" Click="Button_Click"/>
<Button x:Name="button1" Content="이름변경" Grid.Column="1" HorizontalAlignment="Left" Margin="180.2,10,0,0" Grid.Row="2" VerticalAlignment="Top" Width="124" Height="30" Click="Button1_Click"/>
</Grid>
</Window>
[MainWindow.xaml.cs]
using System.Windows;
namespace WpfApp8
{
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
ViewModel v = new ViewModel();
this.DataContext = v;
}
private void Button_Click(object sender, RoutedEventArgs e)
{
ViewModel v = this.DataContext as ViewModel;
MessageBox.Show(v.LastName + "," + v.FirstName);
}
private void Button1_Click(object sender, RoutedEventArgs e)
{
ViewModel v = this.DataContext as ViewModel;
v.FirstName = "길동";
v.LastName = "홍";
}
}
}
[User.cs]
using System.ComponentModel;
using System.Runtime.CompilerServices;
namespace ApfApp8
{
public class User : INotifyPropertyChanged
{
private string _firstName;
public string FirstName
{
get
{
return _firstName;
}
set {
_firstName = value;
RaisePropertyChange();
}
}
private string _lastName;
public string LastName
{
get
{
return _lastName;
}
set
{
_lastName = value;
RaisePropertyChange();
}
}
public event PropertyChangedEventHandler PropertyChanged;
public void RaisePropertyChange([CallerMemberName] string propertyname = null)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyname));
}
// PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyname));
}
}
}
[ViewModel.cs]
using ApfApp8;
namespace WpfApp8
{
class ViewModel : User
{
public ViewModel()
{
FirstName = "KIL-DONG";
LastName = "KIM";
}
}
}

#InotifyPropertyChanged , #StaticResource, #x:Static, #WPF데이터컨텍스트, #데이터컨텍스트, #WPF데이터바인딩, #WPF교육, #WPF강좌, #WPF학원, #DataBinding, #WPFDataBinding
InotifyPropertyChanged , StaticResource, x:Static,WPF데이터컨텍스트, 데이터컨텍스트,데이터바인딩, WPF데이터바인딩, WPF교육, WPF강좌, WPF학원, DataBinding, WPFDataBinding
댓글 없음:
댓글 쓰기