タグ別アーカイブ: WPF

バインディングオブジェクト内の変更をコントロールに反映するには

概要

WPFでコントロールにオブジェクトをBindingしている場合、オブジェクトのプロパティが変更されたときにコントロールの表示も伴って更新されてほしいわけだが、残念ながら更新されない。

これは、更新されたことを通知する機構がオブジェクトに備わっていないからである。 このページではこれの対応策を示す。

対策

まず INotifyPropertyChanged インターフェースを実装

コントロールにプロパティが変更されたことを通知するには、まずバインドするクラスにINotifyPropertyChangedインターフェースを実装しておく。

INotifyPropertyChangedを実装するとPropertyChangedイベントが追加されるので、これをコールするための下記のようなメソッドを作っておく。

public event System.ComponentModel.PropertyChangedEventHandler PropertyChanged;

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

この引数nameには変更されたプロパティの名前を渡す。

そして変更を通知すべきプロパティ(表示を更新する必要のあるプロパティ)のsetアクセサで次のようにコールする。

private string _userId;
public string UserId
{
    get
    {
        return _userId;
    }
    set
    {
        _userId = value;
        OnPropertyChanged("UserId");
    }
}

これでUserIdに値がセットされると、変更が通知されるようになる。

コレクションには ObservableCollection<T> クラス

たとえばTreeViewに階層構造のオブジェクトをバインドしているとする。

オブジェクトの中のコレクションをList<T>などで実装しているとこれらのコレクションに要素が追加もしくは削除されたとき、TreeViewの表示が更新されない。 また、これはコレクションのプロパティからPropertyChangedを呼んでも同じである。

これを自動的に反映されるようにするにはコレクションにObservableCollection<T>クラスを利用すればいい。

ソースコード

以上の実装例を示す。

public class TopLevel : System.ComponentModel.INotifyPropertyChanged
{
    private string _userId;
    public string UserId
    {
        get
        {
            return _userId;
        }
        set
        {
            _userId = value;
            OnPropertyChanged("UserId");
        }
    }
    public ObservableCollection<SecondLevel> SecondLevels { get; set; }

    #region INotifyPropertyChanged メンバー
    public event System.ComponentModel.PropertyChangedEventHandler PropertyChanged;

    protected void OnPropertyChanged(string name)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new System.ComponentModel.PropertyChangedEventArgs(name));
        }
    }
    #endregion
}

参考