はじめに
いつもお世話になっているReactivePropertyなんですけど、使い方を習熟するべく元のソースを見ていたら結構知らない機能があったため、勉強がてら投稿させていただきます。
機能確認用プロジェクト
ReactivePropertySample(github)
環境
ReactiveProperty: 5.1.1 (2018/06/21)
Prism: 6.3.0 (2017/03/25)
.NET Framework: 4.7.2
機能
ReactivePropertySlimとReadOnlyReactivePropertySlim
-
機能説明
軽量なReactivePropertyだそうです。ReactivePropertyとの違いがReactivePropertySlim詳解に書かれているので引用させていただきます。
フィールド数を最小限にしてアロケーションを抑えた(無印はバリデーション系などのためにSubjectやLazyの保持がかなりある)
内部で使ってるSubjectをやめて完全自前管理&Subscription(IDisposable)自体を連結リストのノード自身にすることで、複数Subscribeでのアロケーションをなくした
変更通知の実行をスケジューラー経由で行わず直接する(無印はデフォルトでDispatcher経由になるけれど、パフォーマンス上の問題と、厄介な挙動を時折示していた)
バリデーション系のメソッドを除去
ReactivePropertySlimからObservable Sourceを受けとる機能/コンストラクタを削除(ReadOnlyReactivePropertySlimのみがその機能を持つ)
上記の内容に反しない限り置き換えちゃっても大丈夫な気がしてます。例えば私はMVVMのModelでもReactivePropertyを使用しているのですがスケジューラ―関係やバリデーションは使っていなかったので今後はReactivePropertySlimを使用していこうかと思いました。
後はToReadOnlyReactivePropertyしていたところはToReadOnlyReactivePropertySlimに置き換えるとか。
- 機能確認用
AsyncReactiveCommand
-
参考
AsyncReactiveCommandでWPFのお手軽ダブルクリック抑制
ReactiveProperty v2.9.0とv3.0.0-pre5をリリースしました。 -
機能説明
ReactiveProperty v2.9.0とv3.0.0-pre5をリリースしました。から引用させていただきます。
Subscribeメソッドが非同期メソッドを受け取って、その非同期メソッドが実行中の間は自動的にCanExecuteをFalseにしてくれるというCommandです。
一度ボタンを押したら処理が終わるまでそのボタンの二度押しをできないようにできるみたいです。似たような機能に後述するBusyNotifierがありました。
- 機能確認用
ReactiveTimer
-
参考
MVVMとリアクティブプログラミングを支援するライブラリ「ReactiveProperty v2.0」オーバービュー
ReactiveProperty ver 0.3.0.0 - MとVMのバインディングという捉え方 -
機能説明
ReactiveProperty ver 0.3.0.0 - MとVMのバインディングという捉え方から引用させていただきます。
機能は、Observable.TimerのStop/Start出来る版です。
より便利なTimerなようなのでReactivePropertyを使用しているならばこちらを使用したほうが良さそうです。
- 機能確認用
BooleanNotifier
-
参考
ReactiveProperty ver 0.3.0.0 - MとVMのバインディングという捉え方
ReactivePropertyのNotifier系クラス -
機能説明
bool値を制御する機能でTurnOnやTurnOff、SwitchValueが特徴的です。TurnOnやTurnOffを使用すると値の変化時だけ通知することができます。Valueで直接値を設定することもできますがValueの場合は同じ値を設定しても通知が飛んでしまいます。true-falseの変化時だけ通知が欲しいときなどに使えそうです。
SwitchValueはtrueとfalseが交互に切り替わるのでトグルボタンを作るときに使えそうです。
- 機能確認用
BusyNotifier
- 参考
ReactivePropertyで2度押し防止/ReactiveProperty v2.7.0をリリースしました
- 機能説明
ProcessStartを実行するとtrueになり、ProcessStartの戻り値であるIDisposableをDisposeするとfalseになります。
コードで書くと
using (this.BusyNotifier.ProcessStart())
{
await 重い処理Async();
}
となります。この処理をReactiveCommandのSubscribeに書いてそのコマンドの生成を
var command = this.BusyNotifier.Select(b => !b).ToReactiveCommand()
とすれば二度押しを抑止することができます。ボタンひとつひとつを制御したい場合はAsyncReactiveCommandが有効ですが、一つボタンを押されれば全てのボタンを抑止したいときなどはBusyNotifierのほうが良さげに感じました。
もうひとつの特徴として、処理を並列で実行した場合に、全ての処理でDisposeされるまでBusyNotifierはfalseを維持し続けてくれました。自分のイメージだとTask.WhenAllの戻り値なし版みたいな感じです。それぞれの処理の戻り値には興味なくて、ただ単に非同期処理が終わったことだけが知りたい場合には有効な気がしました。(例えば画面に表示する情報を全部取得し終わってから操作可能にしたいときとか)
- 機能確認用
CountNotifier
-
参考
ReactiveProperty ver 0.3.0.0 - MとVMのバインディングという捉え方
ReactivePropertyのNotifier系クラス -
機能説明
ReactivePropertyのNotifier系クラスから引用させていただきます。
インクリメントとデクリメントを行うクラスです。コンストラクタでインクリメント出来る最大値を指定することもできます。IObservableとして使うことができます。CountChangedStatusはIncrementなのかDecrementなのかEmpty(0になった)のかを表すenumです。
Incrementは、IDisposableを返します。これをDisposeすることで、Incrementを取り消すこともできます。IncrementとDecrementは、引数に数値を渡すことで像現地を指定することができます。
単純にカウンターしても使用できそうですし、CountChangedStatusを監視していればIncrementからDecrementに変化したときだけ(逆もまた然り)を検出できそうです。
- 機能確認用
MessageBroker
- 参考
ReactiveProperty v2.7.4をリリースしました
- 機能説明
Messengerパターンを実現できます。PrismのEventAggregatorでも同じことが実現できました。MessageBrokerのほうは購読後すぐにRxにつなげたりできます。あと呼び出しがシングルトンでした。
- 機能確認用
ScheduledNotifier
- 参考
ReactivePropertyのNotifier系クラス
ReactiveProperty : WPF/SL/WP7のためのRxとMVVMを繋ぐ拡張ライブラリ
- 機能説明
SubjectにISchedulerを合わせたような機能です。OnNextを任意の時間後に発行できます。あとIProgressも実装しているので進捗専用ならSubjectよりこれを使ったほうが良さそうです。
- 機能確認用
Pairwise
-
機能説明
MVVMをリアクティブプログラミングで快適にReactivePropertyオーバービューからまんま引用させていただきます。
以下のショートカットです。
ox.Zip(ox.Skip(1), (x, y) => new OldNewPair(x, y))
OldNewPair型はOldItem, NewItemで値にアクセスできます。
たまに前後値を比較したいときがあるので重宝しています。ひとつskipした同じものをzipして~というのは解っている人がみればわかるんでしょうけどもぱっとみ意図が解りづらいので、Pairwiseという名前を付けてくれたのは共通認識の点で助かります。
- 機能確認用
ReactivePropertyMode
- 参考
MVVMをリアクティブプログラミングで快適にReactivePropertyオーバービュー
ReactiveProperty v5.1.1 をリリースしました
- 機能説明
ReactivePropertyやReactivePropertySlimを初期化するときにReactivePropertyModeを指定することで挙動を変更することができます。
要素 | 説明 |
---|---|
None | 指定なし |
DistinctUntilChanged | この要素を追加すると、同じ値がきたら発火しない。どんな値でも漏らさず流したいなら外した方が良い |
RaiseLatestValueOnSubscribe | Subscribeしたときの最初の一回を実行するか否かを指定できる。設定だけして今までのは流したくないなら外した方が良い |
IgnoreInitialValidationError | SetValidateNotifyError等を設定しておいて最初の一回目のエラーは無視したい場合には追加した方が良い(例えば空の入力を許さないTextBoxだけど画面表示時はエラー表示を出したくないとか) |
Default | DistinctUntilChanged と RaiseLatestValueOnSubscribe |
- 機能確認用