概要
この記事は以下の記事へのアンサーというか、私なりの推測をしたものです。
【WPF】BooleanNotifierをToReactiveCommandしたときの挙動について【ReactiveProperty7.5.1】
BooleanNotifierの挙動が思っていたのと違う?
同じ初期値false
を持つBooleanNotifierとReactivePropertyからReactiveCommandを生成するとCanExcute
の値が異なります。
var booleanNotifier= new BooleanNotifier(initialValue: false);
var reactiveProperty = new ReactiveProperty<bool>(initialValue: false);
BooleanNotifierButtonCommand = booleanNotifier.ToReactiveCommand();
ReactivePropertyButtonCommand = reactiveProperty.ToReactiveCommand();
//BooleanNotifierButtonCommand.CanExcute == true;
//ReactivePropertyButtonCommand.CanExcute == false;
コード的原因
コード的には元記事でも述べられているように、以下のところがまさに原因です。
(BooleanNotifierにはなく、ReactivePropertyでのみ)Subscribeの中でOnNext()が記述されている
でもなんで?(本題)
ここからが記事の本題ですが、では何故BooleanNotifierはそうしないのか?という疑問があるかもしれません。
それは実はSubscribeされたらOnNextをするReactivePropertyのほうが、Rx的にもしくはObserverパターンとしては異質なことをしているから、です。
Observerパターンの説明では通常、Observerが購読(Subscribe
)した直後に値が流れて来ることはなく、Observableが通知(OnNext
)して初めて値がObserverに来ます。
しかし、ReactivePropertyでは異なる動きをします。これはMVVMパターンの中で使われる上でそのほうが便利だからです。それは前述のToReactiveCommand()
でもそうですし、あるReactivePropertyから別のReadOnlyReactivePropertyに変換する場合もそうです。この動きはReactivePropertyのMode
でRaiseLatestValueOnSubscribe
を無効にすれば無くすこともできます。
ただ、この判断には躊躇いもあったようで、途中で破壊的変更をして導入されています。
ReactivePropertyのデフォルトモードが DistinctUntilChanged|RaiseLatestValueOnSubscribe になりました。今まではRaise…が入ってなかったのですが、思うところあって変わりました。例えばCombineLatestは、全てが一度は発火していないと動き出しません。ReactiveCommandの条件に使うなどの場合にRaiseしてくれないと不都合極まりなく、かつ、Subscribeと同時にRaiseすることによる不都合なシーンは逆に少ない。ことを考えると、必然的にデフォルトをどちらに振るべきかは、分かりきった話でした。
というわけで、BooleanNotifierがReactivePropertyと違う挙動をするのは、ReactivePropertyがMVVMパターンを意識して本来のObserverパターンとは違う挙動をするようなクラスだから、です。
じゃあ、BooleanNotifierはどう使うか、というと本来のObserverパターンらしく何かの変更通知です。ロギングやバックアップ処理など、Viewに現在の状態を常に示す、という以外の用途ですね。
余談
実は同じNotifier系でもBusyNotifierはSubscribeされたらOnNextします。これはToReactiveCommand()
などで使われることが想定されたクラスだからです。
https://blog.okazuki.jp/entry/2016/04/09/005825