読者です 読者をやめる 読者になる 読者になる

かずきのBlog@hatena

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

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ですし。