kazuakix の日記

Windows Phone とか好きです

Windows Phone アプリでプロパティの変更を通知する方法

プロパティが変更された事を View に通知するためには INotifyPropertyChanged インタフェースを実装したクラスを作りますよね。

普通の方法

INotifyPropertyChanged インタフェースは PropertyChanged イベントハンドラを実装しないといけないのでこんな感じ。

public class MainPageViewModel : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;
    protected void NotifyPropertyChanged(string propertyName)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}

PropertyChanged を呼び出す手間を減らすための NotifyPropertyChanged を一緒に定義しています。
  
プロパティが変化したときには このイベントを呼ん変更を通知します。

public class MainPageViewModel : INotifyPropertyChanged
{
    private string _name;
    public string Name
    {
        get { return this._name; }
        set 
        {
            this._name = value; 
            // 変更の通知
            NotifyPropertyChanged("Name"); 
        }
    }

これでプロパティの変更が View に通知されるのですが、なんというか...スッキリしませんよね。特にプロパティ名を文字列で渡しているあたり。
 

サンプルアプリで見かける方法

サンプルを見ていると BindableBase という名前のクラスがあって、もう少しだけスマートに INotifyPropertyChanged インタフェースを処理してくれています。

public abstract class BindableBase : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    protected bool SetProperty<T>(ref T storage, T value, [CallerMemberName] String propertyName = null)
    {
        if (object.Equals(storage, value)) return false;
        storage = value;
        this.OnPropertyChanged(propertyName);
        return true;
    }

    protected void OnPropertyChanged([CallerMemberName] string propertyName = null)
    {
        var eventHandler = this.PropertyChanged;
        if (eventHandler != null)
        {
            eventHandler(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}


使い方はこんな感じ。

public class MainPageViewModel : BindableBase
{
    private string _name;
    public string Name
    {
        get { return this._name; }
        set { SetProperty(ref this._name, value); }
    }

ref を指定しないといけないのがちょっとアレですが、だいぶマシになっていますよね。サンプルで見かけて以来、自分のアプリにもコピーして使っていました。
 

Prism の場合

Prism だと その名も ViewModel というクラスがあって、こんな感じになります。

public class MainPageViewModel : ViewModel
{
    private string _name;
    public string Name
    {
        get { return this._name; }
        set { SetProperty(ref this._name, value); }
    }

あれ? 使い方まったく同じですね。
 
この ViewModel の定義はこんな感じ

public class ViewModel : BindableBase, INavigationAware
{
    // 略
}

public abstract class BindableBase : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    protected virtual bool SetProperty<T>(ref T storage, T value, [CallerMemberName] string propertyName = null)
    {
        if (object.Equals(storage, value)) return false;

        storage = value;
        this.OnPropertyChanged(propertyName);

        return true;
    }

    protected void OnPropertyChanged(string propertyName)
    {
        var eventHandler = this.PropertyChanged;
        if (eventHandler != null)
        {
            eventHandler(this, new PropertyChangedEventArgs(propertyName));
        }
    }

    protected void OnPropertyChanged<T>(Expression<Func<T>> propertyExpression)
    {
        var propertyName = PropertySupport.ExtractPropertyName(propertyExpression);
        this.OnPropertyChanged(propertyName);
    }
}

あ、一緒だこれー。

という訳で、サンプルをベースにしてアプリ作っていた人には Prism がとっつきやすいのではないでしょうか?