2015年3月28日土曜日

INotifyPropertyChanged サンプル2

以前にもこちらの記事で INotifyPropertyChanged インターフェイスの例を紹介しましたが、改めて簡易なサンプルで実装内容を紹介します。

INotifyPropertyChanged インターフェイスとは:
バインドデータがプログラム側で変更された際に、ユーザーインターフェイス(UI)にその変更を通知する仕組みを提供します。例えば Label コントロールに DataItem クラスの Name プロパティをバインドする場合、下記のようにクラスの定義、初期化とユーザーコントロールの定義を行います。

データ用クラス
public class DataItem
{
    public string Name { get; set; }
}

データの初期化
public MainWindow()
{
    InitializeComponent();

    // データの生成
    DataItem item = new DataItem() { Name = "Josh" };
    // データを DataContext に割り当て
    this.DataContext = item;
}

ユーザーコントロール
<Label Name="label1" Content="{Binding Path=Name}"
    Margin="194,47,130,0"
    VerticalAlignment="Top" Height="41"
    Background="LightBlue"/>

上記で初動時には問題なく Label コントロールに 「Josh」 が表示されます。

ただし、次のように任意のイベントで動的にバインドデータである DataItem インスタンスの Name プロパティが書き換えられた場合、コンソールには「新しい名前」が出力されますが、UI の Label コントロールはバインドされているプロパティの変更が自動的に通知されないため「Josh」がそのまま残っています。

private void Button_Click(object sender, RoutedEventArgs e)
{
    DataItem item = this.DataContext as DataItem;
    item.Name = "新しい名前";

    Debug.WriteLine(item.Name);
}

INotifyPropertyChanged インターフェイスがなければ、バインドプロパティが変更されたタイミングで改めてユーザーコントロールに対しても明示的に新しい値を持つプロパティを割り当てる必要があり、ロジックと UI がより密結合な状態となってしまいます。ロジックと UI をより疎結合な状態にし、且つ値変更を自動的に通知する仕組みとして INotifyPropertyChanged インターフェイスを利用します。INotifyPropertyChanged インターフェイスはデータクラスに実装していきます。PropertyChangedEventHandler を定義し、OnPropertyChanged イベントをハンドルします。

/*
public class DataItem
{
    public string Name { get; set; }
}
*/
public class DataItem : INotifyPropertyChanged
{
    private string name;
    public string Name
    {
        get
        {
            return name;
        }
        set
        {
            name = value;
            OnPropertyChanged("Name");
        }
    }

    #region INotifyPropertyChanged

    public event PropertyChangedEventHandler PropertyChanged;

    protected void OnPropertyChanged(string name)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(name));
        }
    }

    #endregion
}

参考情報:
INotifyPropertyChanged インターフェイス