MVVMについて

MVVMをかなり使い込んで来たのでいろいろまとめたい内容があるのだがなかなか時間がとれない。
とりあえずポイントをメモ書きしておく

業務アプリでのMVVMでのメリットは

テスト性の向上などはあるが、最大のメリットはテクノロジ非依存に画面ロジックを作成でき保守性・移植性が高くできる点を挙げておこう。

逆にデメリットは

ViewとViewModelの分離など設計時の初期コストが高くてっとり早く作れない点だろう。

MVVMの設計ポイント

以下の3つの要素に分けて画面を整理する

コマンド

ユーザ操作に対する処理でViewModel上のデータや状態に対して影響を与える処理。ViewModel上のメソッドとして実装される。

データ

ユーザが確認・入力する情報。ViewModel上で論理的に適切な構造で保持されプロパティとして実装される。Viewで適切な形式に変換して表示し、入力されたデータはViewModelに設定(通知)される

振る舞い

ユーザが画面操作した時の画面反応処理。Viewの処理として実装。ViewModelのコマンドやデータと連携して実行される。WPF・Sliverlightでは(添付)ビヘイビアやXAMLのコードビハイインドで実装される

FAQ

Q.XAMLのコードビハンドでコードを記述していはいけないのか?

コードビハインドはアドホックなビヘイビアと考える。Viewの責務を越えなければ全く問題ない。

Q.ViewModelでView操作をしてはいけないのか?

テクノロジ依存するようなことはNGだがViewを抽象化してアクセスすることはOK。ViewModelから論理的なイベントを通知してView側で処理するような方式であれば問題ない。

Q.ViewでViewModelを操作してはいけないのか?

ViewModelからViewよりはかなり緩和してかまわない。理由は通常Viewは特定のViewModelを前提にしており、論理的なレベルでは依存しているためである。(緩和範囲:バインドで実装できないプロパティへの値操作、特殊なイベントの発生時のViewModelのコマンドの実行、禁止事項:ViewModelのプロパティの演算)

Q.ViewModelでコントロールの状態に応じて処理を振り分けたいがどのようにすればよいか?

コントロールの状態をViewModelのプロパティにバインドしてViewModelで確認できるようにする。
たとえば、CheckBoxのチェック状態にバインドするプロパティを作成し、該当処理から現在の状態値を確認して処理を振り分ける。

Q.入力検証はViewとViewModelどちらの責務か?

どちらもありえる。個人的にはViewModelが属性などのメタ情報を提供してView側が自動的に入力検証を行う仕組みが好みである。IMEの制御や最大入力長、入力文字制限も同様の仕組みを利用することができる。要は、ViewがViewModelのメタ情報を読みとり自動的に適切なビヘイビアを付与するということである。

Q.MVVMで複雑な画面制御をすることは難しいのではないか?

複雑の内容によるが項目の活性・非活性などの表示制御は、ViewModelのBOOL型プロパティをバインドすると簡単に実装できる。DRAG&DROPなどの操作もViewのビヘイビアとして実装できる。
逆にビジネスルールに由来する複雑さは、ViewModel側はプレーンなクラスでありOOPのテクニックを利用することで制御しやすい。

Q.INotifyPropertyChangedは必ず実装する必要があるか

必ずしも実装する必要はない。
ViewModelからViewに明示的にデータ更新を通知するコマンドを用意するなどの方式で代用することができる。
なおWPFでは強参照が残る場合がありメモリリークの原因になるためできるだけ実装することを勧める。

Q.ViewModelのフォーカス制御はどのように行えばよいか

フォーカス制御はView(ビヘイビア)で実装することになる。。
特定のコントロールをViewModelから指し示すことはNGなので、論理的な状態を規定してViewModelからViewに通知する。
たとえば、画面の状態として初期化・編集中・完了などの状態を定義してViewModelからViewに状態変更のイベントを出す。受け取ったViewは該当画面における初期化状態の最初の入力コントロールにフォーカスを設定するようにする。

Q.入力エラー時のフォーカス制御では特定のコントロールを指し示す必要があるのでは

必須入力や型チェックなどの単項目の入力エラーの場合はViewで制御することが可能である。どうしてもViewModelで制御したい場合はバインドしているプロパティの名前を利用してViewに間接的にどのコントロールかを通知する。多くのケースはこの方法で対応可能である。より複雑なケースについては、汎用的な方法としては、入力エラーコードをViewModelからViewに通知して個別のビヘイビアとして実装する

Q.画面遷移はViewとViewModelどちらの責務か?

単なる画面表示以上の責務はどちらでもない。画面遷移コントローラを別途導入することをお勧めする。画面遷移にはセキュリティ要件なども含まれる可能性があり、より大局的な制御が必要になる。