13장. WPF 데이터바인딩 실습, INotifyPropertyChanged, PropertyChanged 이용

참조

목적

  • WPF INotifyPropertyChanged, PropertyChanged 이용하여 데이터바인딩 실습합니다.

INotifyPropertyChanged 인터페이스, PropertyChanged 이벤트를 이용한 데이터 바인딩

1

  • 데이터바인딩에서 소스 객체는 UI 컨트롤 일수도 있지만 위 그림처럼 소스 객체가 C#의 일반 클래스가 될 수도 있는데 이 경우 프로퍼티(속성)의 값이 변경되는 경우 이를 타겟 객체에 알릴 수 있는 메커니즘이 필요합니다.
  • WPF 데이터 바인딩은 이벤트가 INotifyPropertyChanged 인터페이스를 구현한 클래스안에 정의되어 있으면 이벤트를 찾는데 소스 객체의 속성값의 변경을 통지하기 위해서는 이 인터페이스를 상속받아 구현하고 PropertyChangedEventHandler 델리게이트를 기본으로 하는 PropertyChanged 이벤트를 정의해야 합니다.
  • PropertyChaneged 이벤트를 발생시킬 때의 처음 인자는 this 이며 두번째 인자는 PropertyChangedEventArgs 타입의 객체입니다. PropertyChangedEventArgs는 string 타입의 PropertyName이라는 프로퍼티가 정의되어 있는데 프로퍼티를 구별하기 위해 사용합니다. 그래서 PropertyChangedEventArgs를 new 하면서 프로퍼티 이름을 넣어 줍니다.
  • CallerMemebrName 특성(Attribute)을 통해 어느 프로퍼티(속성)에서 PropertyChanged 이벤트가 발생했는지 확인 가능 합니다. 만약 CallerMemberName 특성(Attribute)이 없으면 프로퍼티(속성) 이름을 문자열로 지정해야 합니다.
public void RaisePropertyChnage([CallerMemberName]string propertyname = null)
{
    if(PropertyChanged != null)
    {
        PropertyChanged(this, new PropertyChangedEventArgs(propertyname));
    }
    //PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyname));
}
  • 위의 방법이 다수의 프로퍼티를 다루는 좋은 방법 입니다. 하나의 PropertyChanged 이벤트가 모든 프로퍼티(속성)에 대한 변경을 처리할 수 있기 때문입니다.

INotifyPropertyChanged 인터페이스를 이용한 데이터 바인딩 실습

  • User 모델을 상속받은 ViewModel 객체가 데이터바인딩의 소스 객체가 되고 이것이 UI 쪽 TextBox 컨트롤과 데이터바인딩이 이루어 지는데 최초 ViewModel에서 LastName, FirstName을 KIM, KIL_DONG 으로 셋팅하고 이 값이 UI 쪽 컨트롤에 표시됩니다.
  • "이름변경" 버튼을 클릭하면 ViewModel에서 LastName, FirstName 을 홍길동으로 변경하는데 이것이 UI쪽 컨트롤에 데이터바인딩되어 UI TextBox 컨트롤에 표시됩니다.

User.cs

using System.ComponentModel;
using System.Runtime.CompilerServices;

namespace WPF13_Test
{
    //Model (Data를 담을 객체)
    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

namespace WPF13_Test
{
    public class ViewModel : User
    {
        public ViewModel()
        {
            FirstName = "KIL-DONG";
            LastName = "HONG";
        }
    }
}

MainWindow.xaml

<Window x:Class="WPF13_Test.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:WPF13_Test"
        mc:Ignorable="d"
        Title="MainWindow" Height="250" Width="450">
    <Window.DataContext>
        <local:ViewModel/>
    </Window.DataContext>

    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="Auto"/>
            <ColumnDefinition Width="Auto"/>
        </Grid.ColumnDefinitions>

        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="Auto"/>
        </Grid.RowDefinitions>

        <TextBlock Text="First Name" Grid.Column="0" Grid.Row="0"
                   Margin="5"/>
        <TextBox x:Name="tb_FirstName"
                 Grid.Row="0" Grid.Column="1"
                 Margin="5"
                 Width="300"
                 HorizontalAlignment="Center"
                 VerticalAlignment="Center"
                 Text="{Binding Path=FirstName, 
                                Mode=TwoWay, 
                                UpdateSourceTrigger=PropertyChanged}"/>         
        <TextBlock Text="Last Name" Grid.Column="0" Grid.Row="1"
                   Margin="5"/>
        <TextBox x:Name="tb_LastName"
                 Grid.Row="1" Grid.Column="1"
                 Margin="5"
                 Width="300"
                 HorizontalAlignment="Center"
                 VerticalAlignment="Center"
                 Text="{Binding Path=LastName, 
                                Mode=TwoWay, 
                                UpdateSourceTrigger=PropertyChanged}"/>

        <Grid Grid.Row="2" Grid.Column="1">
            <Grid.ColumnDefinitions>
                <ColumnDefinition/>
                <ColumnDefinition/>
            </Grid.ColumnDefinitions>

            <Button Grid.Column="0" Margin="2"
                    x:Name="uiBtn_Show"
                    Click="uiBtn_Show_Click"
                    Content="보기"/>

            <Button Grid.Column="1" Margin="2"
                    x:Name="uiBtn_Change"
                    Click="uiBtn_Change_Click"
                    Content="이름변경"/>
        </Grid>
    </Grid>
</Window>

MainWindow.xaml.cs

using System.Windows;

namespace WPF13_Test
{
    /// <summary>
    /// MainWindow.xaml에 대한 상호 작용 논리
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }

        /// <summary>
        /// MessageBox 출력 클릭 이벤트 핸들러
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void uiBtn_Show_Click(object sender, RoutedEventArgs e)
        {
            MessageBox.Show($"이름 : {tb_FirstName.Text.ToString()}\n마지막 이름 : {tb_LastName.Text.ToString()}");
        }

        /// <summary>
        /// 이름을 영어에서 한글로 변경하는 이벤트 핸들러
        /// ViewModel 을 변경
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void uiBtn_Change_Click(object sender, RoutedEventArgs e)
        {
            ViewModel vm = this.DataContext as ViewModel;
            vm.FirstName = "길동";
            vm.LastName = "홍";
        }
    }
}
  • 실행결과

2

728x90

이 글을 공유하기

댓글

Designed by JB FACTORY