かずきのBlog@hatena

日本マイクロソフトに勤めています。XAML + C#の組み合わせをメインに、たまにASP.NETやJavaなどの.NET系以外のことも書いています。掲載内容は個人の見解であり、所属する企業を代表するものではありません。

ポータブルライブラリにもってこいのINotifyPropertyChangedの実装クラス

最近ポータブルライブラリがあついです!何があつくさせるかというと、Microsoft.Bcl.AsyncをNuGetで追加すればasync/awaitが使える上にCallerMemberNameAttributeとかC# 5.0の機能が使えちゃうところですね。しかも以下の幅広いプラットフォームで。

これはもう、ポータブルライブラリに入れれるものはガシガシ入れていくのを今から検討をはじめても早くはないと思います。早くはないと、ちょっと弱気なのはMicrosoft.Bcl.Asyncが、まだ正式リリースじゃないからです。お仕事では使わずにお試し程度に触れておくくらいでちょうどいいのかなと思います。

とりあえず、最初にぱっと思いついたのがINotifyPropertyChangedの実装の基本クラス。こいつは、ポータビリティ抜群ですね。SLでもWPでも.NET FwでもWinRTでも一番よく書かれてるコードの一つだと思います。

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

public abstract class NotificationObject : INotifyPropertyChanged
{
    protected NotificationObject() { }

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

これに、Windows ストア アプリのテンプレートで作った時に追加されるBindableBaseのSetPropertyみたいなメソッドも追加してやりましょう。

public abstract class NotificationObject : INotifyPropertyChanged
{
    protected NotificationObject() {}

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

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

        store = value;
        this.OnPropertyChanged(propertyName);
        return true;
    }
}

こんなクラスを作っておくと、ポータブルライブラリの対象のバージョンから共通に使えちゃうINotifyPropertyChangedの実装クラスの出来上がり。
小さなことからこつこつとね。

使い方

これでSL4以上, WP7.5以上, .NET 4以上, WinRTでこんなにすっきりとプロパティが定義できちゃいますね!

public class Person : NotificationObject
{
    private string name;
    public string Name
    {
        get { return this.name; }
        set
        {
            this.SetProperty(ref name, value);
        }
    }
}