article最近になってWPFで作りたいものができたので、勉強したことをメモしてみたいと思います。Formsの頃のようにコードビハインドへ記述するやり方では、この機能を活かすことはできないんですね。そこでプログラマーは、できる限りMVVMパターンに沿ったコードの書き方を「意識して」行なわなくてはダメだというわけです。面倒くさがりな私がMVVMパターンをできるだけ簡単に記述できないかと調べてみたところ、「Prism」と「ReactiveProperty」を使うのが良さそうだと分かりました。PrismPrismにはMVVMパターンをサポートする機能が含まれています。現時点でバージョンは6.1.0。NuGetで「Prism.Core」をインストールしておきましょう。ReactivePropertyデータバインドに対応したObservableなプロパティを作成できます。現時点でバージョンは2.4.2。NuGetで「ReactiveProperty」をインストールすると、依存関係にあるReactiveExtensions(Rx-XXXX)もインストールされます。簡単MVVMまずはサンプルコードから。2つの数値を足し合わせて結果を表示するだけのWPFアプリです。&lt;/StackPanel&gt;&lt;/Window&gt;実行結果はこちら。2つのテキストボックスに入力された数値を足し合わせた結果を表示するアプリです。空白やdouble以外の文字列は、Validationによってはじかれます。数値を正しく入力するとSumボタンが押下できるようになります。Modelの作り方MVVMにおけるModelは、ViewModelにプロパティの変更を通知できるよう実装する必要があります。標準では「System.ComponentModel.INotifyPropertyChanged」インターフェイスを実装するわけですが、Prismの「Prism.Mvvm.BindableBase」クラスを継承すると、プロパティ変更通知の仕組みを少しだけ楽に記述できます。}}SetProperty()にプロパティの実体となる変数を渡すことで、値が変更された際にPropertyChangedイベントが発生します。SetProperty()を使わずに明示的にPropertyChangedを発生させるには、OnPropertyChanged()を使用します。}}ViewModelの作り方ViewModelはModelのプロパティを監視する必要があり、またViewに自身のプロパティの変更を通知しなくてはなりません。ReactivePropertyの「Reactive.Bindings.ReactiveProperty」クラスは、自らが監視者となってINotifyPropertyChangedなどを監視しつつ、自身もまたIObservableとして変更通知を行なうことができます。Modelを監視する方法は以下の通り。}}ViewがViewModelをバインドする際には、「Value」プロパティを使用します。X.Value}"/&gt;&lt;/StackPanel&gt;ViewModelにおけるValidationViewModelがViewから受けとった値をModelと同期する際、Validationを設定することができます。先ほどの例では、double値に変換できる文字列のみを許可するよう、「System.ComponentModel.DataAnnotations.ValidationAttribute」クラスを継承した自作属性を使用しました。ValidationAttributeを自作する方法は簡単で、IsValid()をオーバーライドするだけです。}}ValidationAttribute属性をもとにReactivePropertyがValidationを行なうには、以下のようにします。}}このように、SetValidateAttribute()でValidationAttribute属性のついたプロパティを指定することで、それに対応するValidationが実行されるようになります。この場合、IDataErrorInfoによるエラーチェックとなります。エラーをViewが受け取るには、ViewのBindingに「ValidatesOnDataErrors=True」を指定しましょう。INotifyDataErrorInfoによるエラーチェックも可能です。ここで、ToReactivePropertyAsSynchronized()の引数の意味を解説します。m.X)はSystem.Linq.Expressions.Expression型で、監視するプロパティを指定しています。double.Parse(s))はそれぞれ、監視対象からReactivePropertyへの変換、ReactivePropertyから監視対象への変換を指定しています。4番目の引数は、監視対象の値が変更された際のReactivePropertyの挙動を指定しています。「ReactivePropertyMode.DistinctUntilChanged」を指定すると、監視対象から変更通知はあったけれども実際の値は変化していない場合に、自身は変更通知を発行しません。指定しないと、同じ値でも変更通知を発行します。「ReactivePropertyMode.RaiseLatestValueOnSubscribe」を指定すると、Subscribe()された瞬間に最新の値(無ければ初期値)を一度発行するようになります。指定しないと、実際に値が更新されるまでは何も発行しません。この2つのフラグはデフォルト値です。最後の引数(true)は、Validationでエラーがあった場合に、監視対象への値の書き込みをしないかどうかを指定しています。デフォルトはfalseです。ViewModelのCommandViewからViewModelの処理を呼び出せるように、ViewModel内にCommandを用意する必要がありますが、Commandを簡単に記述できる「Reactive.Bindings.ReactiveCommand」があります。ReactiveCommandは、CanExecute()をIObservableから生成することができます。}}ToReactiveCommand()によりReactiveCommandを生成しています。「ReactiveProperty.ObserveHasErrors」は、Validationのエラーの有無が変化した時にboolを発行するIObservableです。CombineLatest()によりXとYのエラー状況を合算して、両方ともエラーが無い時にtrueとなるCanExecute()になります。ReactiveCommandは、Execute()時に発行されるIObservableなので、コマンドの実体はSubscribe()で記述すればOKです。SendSum.Subscribe()で使用しているMessengerについては、この後説明します。ViewModelとMessengerViewModelからViewに命令を出すために、ViewModelがViewのインスタンスを持つわけにはいきません。そこでMessengerパターンを適用します。Messengerは、ViewとViewModelの間を仲介します。Messengerには、ViewModelから発行されたメッセージを受けとり、Viewへと通知する役割を持たせます。「Prism.Events.EventAggregator」がMessengerの機能を持っているので、それを継承したシングルトンのクラスを定義します。}}あとは、これを使用してメッセージをPublishしてやればいいです。}}「Prism.Events.PubSubEvent」に指定するジェネリック型は、Publish()で発行するメッセージの型です。Viewの作り方Viewのコードビハインドで、Messengerのメッセージ受信時の動作を登録しておきましょう。}}XAML側では、「ReactiveProperty.Value」を普通にBindingするだけです。ViewとEventViewからViewModelへの命令はCommandで記述することが望ましいです。EventとCommandを関連づけるには「System.Windows.Interactivity.InvokeCommandAction」を使用します。2016/02/17追記:「System.Windows.Interactivity.InvokeCommandAction」では、イベントのEventArgsを取得することができません。代わりに「Prism.Interactivity.InvokeCommandAction」を使用することで、CommandのパラメータとしてEventArgsを受けとることができます。これを使用するためには、NuGetから「Prism.Wpf」をインストールする必要があります。下記コードも修正しておきます。&lt;/StackPanel&gt;&lt;/Window&gt;Eventの発行をReactivePropertyが受けとるには、「Reactive.Bindings.Interactivity.EventToReactive」を使用します。以下の例では、マウスをWindow上でドラッグすると、ドラッグ中のマウス座標の最新5件を表示します。}}「Reactive.Bindings.ReactiveCollection」は、発行された値を全てコレクションに保存するという動作をします。最新5件のみを保持するよう、CollectionChangedイベント中に古いデータを削除するよう指示しています。RemoveAt()で削除しようとすると例外が発生します。これは、CollectionChangedイベント中にコレクションを変更できないためです。代わりにRemoveAtOnScheduler()を使用することで、この問題を回避できます。ReactivePropertyやReactiveCollectionには、デフォルトで「System.Reactive.Concurrency.UIDispatcherScheduler」が設定されています。このスケジューラは指定された処理をUIスレッド上で実行する働きがあります。終わりにWPFを勉強し始めたばかりの私ですので、表面的な部分しか触れられませんでした。MVVMに沿ってコーディングするには何かと工夫が必要そうですから、今後少しずつ研鑽を積みたいと思います。最近になってWPFで作りたいものができたので、勉強したことをメモしてみたいと思います。Formsの頃のようにコードビハインドへ記述するやり方では、この機能を活かすことはできないんですね。そこでプログラマーは、できる限りMVVMパターンに沿ったコードの書き方を「意識して」行なわなくてはダメだというわけです。面倒くさがりな私がMVVMパターンをできるだけ簡単に記述できないかと調べてみたところ、「Prism」と「ReactiveProperty」を使うのが良さそうだと分かりました。#PrismPrismにはMVVMパターンをサポートする機能が含まれています。現時点でバージョンは6.1.0。NuGetで「Prism.Core」をインストールしておきましょう。#ReactivePropertyデータバインドに対応したObservableなプロパティを作成できます。現時点でバージョンは2.4.2。NuGetで「ReactiveProperty」をインストールすると、依存関係にあるReactiveExtensions(Rx-XXXX)もインストールされます。#簡単MVVMまずはサンプルコードから。2つの数値を足し合わせて結果を表示するだけのWPFアプリです。SendSum}"/></StackPanel></Window>```実行結果はこちら。![20160124_01.JPG](https://qiita-image-store.s3.amazonaws.com/0/53668/aad87edf-abc9-bfc7-e84f-89325acc682e.jpeg)2つのテキストボックスに入力された数値を足し合わせた結果を表示するアプリです。![20160124_02.JPG](https://qiita-image-store.s3.amazonaws.com/0/53668/639ddefd-0510-8ccc-405f-5a111cda83e2.jpeg)空白やdouble以外の文字列は、Validationによってはじかれます。![20160124_03.JPG](https://qiita-image-store.s3.amazonaws.com/0/53668/73344204-19f0-6a03-0323-dbd9b67dcd42.jpeg)数値を正しく入力するとSumボタンが押下できるようになります。![20160124_04.JPG](https://qiita-image-store.s3.amazonaws.com/0/53668/c658c675-e4aa-1ef0-a26f-d3267a05e834.jpeg)結果が表示されます。#Modelの作り方MVVMにおけるModelは、ViewModelにプロパティの変更を通知できるよう実装する必要があります。標準では「System.ComponentModel.INotifyPropertyChanged」インターフェイスを実装するわけですが、Prismの「Prism.Mvvm.BindableBase」クラスを継承すると、プロパティ変更通知の仕組みを少しだけ楽に記述できます。}}}```SetProperty()にプロパティの実体となる変数を渡すことで、値が変更された際にPropertyChangedイベントが発生します。SetProperty()を使わずに明示的にPropertyChangedを発生させるには、OnPropertyChanged()を使用します。value;OnPropertyChanged();}}}}```#ViewModelの作り方ViewModelはModelのプロパティを監視する必要があり、またViewに自身のプロパティの変更を通知しなくてはなりません。ReactivePropertyの「Reactive.Bindings.ReactiveProperty<T>」クラスは、自らが監視者となってINotifyPropertyChangedなどを監視しつつ、自身もまたIObservableとして変更通知を行なうことができます。Modelを監視する方法は以下の通り。x.Id).ToReactiveProperty();}}```ViewがViewModelをバインドする際には、「Value」プロパティを使用します。X.Value}"/></StackPanel>```##ViewModelにおけるValidationViewModelがViewから受けとった値をModelと同期する際、Validationを設定することができます。先ほどの例では、double値に変換できる文字列のみを許可するよう、「System.ComponentModel.DataAnnotations.ValidationAttribute」クラスを継承した自作属性を使用しました。ValidationAttributeを自作する方法は簡単で、IsValid()をオーバーライドするだけです。d);}}```ValidationAttribute属性をもとにReactivePropertyがValidationを行なうには、以下のようにします。X);}}```このように、SetValidateAttribute()でValidationAttribute属性のついたプロパティを指定することで、それに対応するValidationが実行されるようになります。この場合、IDataErrorInfoによるエラーチェックとなります。エラーをViewが受け取るには、ViewのBindingに「ValidatesOnDataErrors=True」を指定しましょう。INotifyDataErrorInfoによるエラーチェックも可能です。***ここで、ToReactivePropertyAsSynchronized()の引数の意味を解説します。m.X)はSystem.Linq.Expressions.Expression型で、監視するプロパティを指定しています。double.Parse(s))はそれぞれ、監視対象からReactivePropertyへの変換、ReactivePropertyから監視対象への変換を指定しています。4番目の引数は、監視対象の値が変更された際のReactivePropertyの挙動を指定しています。「ReactivePropertyMode.DistinctUntilChanged」を指定すると、監視対象から変更通知はあったけれども実際の値は変化していない場合に、自身は変更通知を発行しません。指定しないと、同じ値でも変更通知を発行します。「ReactivePropertyMode.RaiseLatestValueOnSubscribe」を指定すると、Subscribe()された瞬間に最新の値(無ければ初期値)を一度発行するようになります。指定しないと、実際に値が更新されるまでは何も発行しません。この2つのフラグはデフォルト値です。最後の引数(true)は、Validationでエラーがあった場合に、監視対象への値の書き込みをしないかどうかを指定しています。デフォルトはfalseです。##ViewModelのCommandViewからViewModelの処理を呼び出せるように、ViewModel内にCommandを用意する必要がありますが、Commandを簡単に記述できる「Reactive.Bindings.ReactiveCommand」があります。ReactiveCommandは、CanExecute()をIObservable<bool>から生成することができます。Messenger.Instance.GetEvent<PubSubEvent<double>>().Publish(_model.Sum()));}}```ToReactiveCommand()によりReactiveCommandを生成しています。「ReactiveProperty.ObserveHasErrors」は、Validationのエラーの有無が変化した時にboolを発行するIObservableです。CombineLatest()によりXとYのエラー状況を合算して、両方ともエラーが無い時にtrueとなるCanExecute()になります。ReactiveCommandは、Execute()時に発行されるIObservable<object>なので、コマンドの実体はSubscribe()で記述すればOKです。SendSum.Subscribe()で使用しているMessengerについては、この後説明します。##ViewModelとMessengerViewModelからViewに命令を出すために、ViewModelがViewのインスタンスを持つわけにはいきません。そこでMessengerパターンを適用します。Messengerは、ViewとViewModelの間を仲介します。Messengerには、ViewModelから発行されたメッセージを受けとり、Viewへと通知する役割を持たせます。「Prism.Events.EventAggregator」がMessengerの機能を持っているので、それを継承したシングルトンのクラスを定義します。}}}```あとは、これを使用してメッセージをPublishしてやればいいです。Messenger.Instance.GetEvent<PubSubEvent<double>>().Publish(_model.Sum()));}}```「Prism.Events.PubSubEvent<T>」に指定するジェネリック型は、Publish()で発行するメッセージの型です。#Viewの作り方Viewのコードビハインドで、Messengerのメッセージ受信時の動作を登録しておきましょう。MessageBox.Show(d.ToString()));}}```XAML側では、「ReactiveProperty.Value」を普通にBindingするだけです。##ViewとEventViewからViewModelへの命令はCommandで記述することが望ましいです。EventとCommandを関連づけるには~~「System.Windows.Interactivity.InvokeCommandAction」を使用します~~。>2016/02/17追記:>「System.Windows.Interactivity.InvokeCommandAction」では、イベントのEventArgsを取得することができません。>代わりに「Prism.Interactivity.InvokeCommandAction」を使用することで、CommandのパラメータとしてEventArgsを受けとることができます。>これを使用するためには、NuGetから「Prism.Wpf」をインストールする必要があります。>下記コードも修正しておきます。Command}"/></i:EventTrigger></i:Interaction.Triggers></ListBox></StackPanel></Window>```***Eventの発行をReactivePropertyが受けとるには、「Reactive.Bindings.Interactivity.EventToReactive」を使用します。以下の例では、マウスをWindow上でドラッグすると、ドラッグ中のマウス座標の最新5件を表示します。MouseXY.RemoveAtOnScheduler(0);};}}```「Reactive.Bindings.ReactiveCollection<T>」は、発行された値を全てコレクションに保存するという動作をします。最新5件のみを保持するよう、CollectionChangedイベント中に古いデータを削除するよう指示しています。RemoveAt()で削除しようとすると例外が発生します。これは、CollectionChangedイベント中にコレクションを変更できないためです。代わりにRemoveAtOnScheduler()を使用することで、この問題を回避できます。ReactivePropertyやReactiveCollectionには、デフォルトで「System.Reactive.Concurrency.UIDispatcherScheduler」が設定されています。このスケジューラは指定された処理をUIスレッド上で実行する働きがあります。#終わりにWPFを勉強し始めたばかりの私ですので、表面的な部分しか触れられませんでした。MVVMに沿ってコーディングするには何かと工夫が必要そうですから、今後少しずつ研鑽を積みたいと思います。