さて、かなり前に書いた記事があります。
こいつの欠点は購読したあと解除方法がないことですね。辛い。
今ならどうする?
ということで今ならReactive Extensionsという素敵なものがあります。例えばこんなINotifyPropetyChangedを実装したクラスがあるとします。
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(); } } }
PropertyChangedイベントを購読するにはObservableのFromEventを使ってさくっと書けます。
var p = new Person(); Observable.FromEvent<PropertyChangedEventHandler, PropertyChangedEventArgs>( h => (s, e) => h(e), h => p.PropertyChanged += h, h => p.PropertyChanged -= h) .Where(e => e.PropertyName == "Name") .Subscribe(_ => { Console.WriteLine(p.Name); }); p.Name = "tanaka";
Rxの基本的なFromEventの書き方ですね。なかなか慣れない…!!毎回FromEvent書くのはだるいので拡張メソッドにしてやります。
publicstaticclass PropertyChangedExtensions { publicstatic IObservable<PropertyChangedEventArgs> ObserveProperty(this INotifyPropertyChanged self, string propertyName) { return Observable.FromEvent<PropertyChangedEventHandler, PropertyChangedEventArgs>( h => (s, e) => h(e), h => self.PropertyChanged += h, h => self.PropertyChanged -= h) .Where(e => e.PropertyName == propertyName); } }
こうすると、とてもすっきりします。
var p = new Person(); p.ObserveProperty("Name") .Subscribe(_ => { Console.WriteLine(p.Name); }); p.Name = "tanaka";
もうちょっとタイプセーフに行きたいならこんな拡張メソッドも追加してやるといいです。
publicstatic IObservable<PropertyChangedEventArgs> ObserveProperty<TProp>(this INotifyPropertyChanged self, Expression<Func<TProp>> propertyName) { var name = ((MemberExpression)propertyName.Body).Member.Name; return self.ObserveProperty(name); }
もっとすっきり。
var p = new Person(); p.ObserveProperty(() => p.Name) .Subscribe(_ => { Console.WriteLine(p.Name); }); p.Name = "tanaka";
ReactivePropertyには…
こういう感じのことをしてくれる便利メソッドがあります。
// using Codeplex.Reactive.Extensions; var p = new Person(); p.ObserveProperty(o => o.Name) .Subscribe(value => { Console.WriteLine(value); }); p.Name = "tanaka";
なんとObservePropertyの後ろに流れる値は、プロパティの値という親切設計。ここらへんid:neueccさんのセンスが光ってると思います。細かいところですが。
まとめ
便利メソッドだけ使うということでReactiveProperty入れてみてもいいんではないでしょうかという宣伝でした。