かずきのBlog@hatena

すきな言語は C# + XAML の組み合わせ。Azure Functions も好き。最近は Go 言語勉強中。日本マイクロソフトで働いていますが、ここに書いていることは個人的なメモなので会社の公式見解ではありません。

ReactivePropertyの便利なINotifyPropertyChangedとINotifyCollectionChangedを監視する拡張メソッド

ReactivePropertyは、XAMLで使うのがしっくりきますが、Codeplex.Reactive.Extensions名前空間には、それ以外にも使える便利なメソッドが詰まってます。その中でも汎用的なINotifyPropertyChangedとINotifyCollectionChangedを監視するメソッドを紹介します。

INotifyPropertyChangedの拡張メソッド

ObservePropertyという拡張メソッドがあります。これはExpressionTreeで監視対象のプロパティを指定することで、そのプロパティを監視するIObservable>T<を作成できます。

例を以下に示します。

このようなPersonクラスがあるとして…

public class Person : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;
    private void OnPropertyChanged([CallerMemberName]string propertyName = null)
    {
        var h = this.PropertyChanged;
        if (h != null) { h(this, new PropertyChangedEventArgs(propertyName)); }
    }

    private string name;

    public string Name
    {
        get { return this.name; }
        set
        {
            this.name = value;
            this.OnPropertyChanged();
        }
    }
}

Nameプロパティを監視するコードはこうなります。

var p = new Person();
p.ObserveProperty(x => x.Name)
    .Subscribe(x => Console.WriteLine("変更されました {0}", x));

p.Name = "tanaka";
p.Name = "kimura";

実行すると以下のようになります。

変更されました
変更されました tanaka
変更されました kimura

最初のSubscribeした時点での値がいらなかったらSkip(1)すればいいです。

INotifyCollectionChangedの拡張メソッド

INotifyCollectionChangedのを監視するのは、CollectionChangedAsObservable拡張メソッドです。

これは、CollectionChangedイベントが発行されるたびに値を通知するIObservable>NotifyCollectionChangedEventArgs<を返します。使い方は以下のようになります。

var c = new ObservableCollection<Person>();

c.CollectionChangedAsObservable()
    .Subscribe(x => Console.WriteLine("コレクションに変更がありました"));

c.Add(new Person { Name = "tanaka" });
c.Add(new Person { Name = "kimura" });

実行するとこんな結果になります。

コレクションに変更がありました
コレクションに変更がありました

ObservableCollection>T<限定になりますが、タイプセーフな監視メソッドも用意されています。

ObserveXXXXChangedメソッドでXXXXにはAddやRemoveやReplaceやMoveやResetなどがあります。これは、NotifyCollectionChangedEventArgsを用途ごとに使いやすいように加工したものになっています。

まとめ

ReactiveProperty全部つかうのが重たかったら、該当メソッドだけ切り出して使うのもありかもしれないですね。OSSですし。