Livetによる画面遷移と選択要素受け渡しのサンプル

MVVMパターンでよく問題となるのが、画面遷移 の問題です。
単一画面であれば、View と ViewModel をバインド機構を使って疎結合にできるため、なんら問題は生じませんが、画面遷移を行う場合、ViewModel から Window を起動すると View - ViewModel 間で密結合が発生します。
また View のコードビハインドで画面を起動すると、実装が複雑化するのに加え、View に依存する分 MVVM の利点であるテスト容易性が失われます。疎結合を維持しテスト容易性を保持したまま、画面遷移を行う方法はあるのでしょうか?そこで便利なのが MVVM インフラである Livetメッセンジャー機能です。
これは Livet 特有の機能でして、ViewModel から View に対し各種メッセージを送信でき、またどのビューを対象とするか指定する必要もなく、疎結合を保持したまま送信できるのが特徴です。



メッセンジャーを使えば、ViewModel 内で子画面の ViewModel のインスタンスを生成でき、親画面で保持する Model のインスタンスを渡すことも容易になります。


最近各所で

画面遷移時にどうやって選択要素のインスタンスを渡すかわからない

とか

Livet による画面遷移の方法がわからない

とか

子画面の変更を親画面に通知するにはどうすればいいの?

という質問を見かけたので、Livet のメッセンジャー機能を利用したサンプルを作ってみました。以下はあくまで一例であり、最適解を保証するものではありませんが、MVVM における画面遷移の有効なサンプルだと思ってます。

サンプルプロジェクトのダウンロード:SampleWPFApplication.zip


Model

まず Modelです。ありきたりですが Person クラスと Person のコレクションを生成するファクトリクラスを用意しました。Person クラスは Livet の変更通知用基底クラスである NotificationObject を継承し、インスタンスの更新を考慮して、ICloneable インターフェイスも実装しました。あと三つのプロパティのうち名前・住所の二つの二つのプロパティについては変更が直ちに通知されるよう変更通知プロパティにしています。Person オブジェクトのコレクションは Persons.Create メソッドを介して取得します。

ViewModel

ViewModel です。親となるマスタ画面のビューモデルで、Person オブジェクトのインスタンスを保持します。このクラスで最も着目して欲しいのが、60行目、Edit メソッド内で実装しているメッセンジャーです。この行で、生成した編集画面用 ViewModel のインスタンスと実行コマンド名を送信しています。

子画面である編集画面用のビューモデルです。コンストラクタのパラメータに選択要素である Person オブジェクトが渡されます。View にバインドされるのはコピーオブジェクトの方になり、更新時にコピーオブジェクトの変更内容がオリジナルに反映されるよう実装してます。また CancelCommand と UpdateCommand では、画面終了用に WindowActionMessage を使ってメッセージをView に送信してます。

View

マスタである社員リスト画面の XAML です。DataGrid 上でダブルクリックすると選択要素の編集画面が起動するよう MouseBinding を使ってます。このXAML で一番注目して欲しいのが18行から20行の記述で、InteractionMessageTrigger と TransitionInteractionMessageAction を使って、ViewModel から送信されたメッセージを受信し、SubWindow をモーダルで起動するようにしています。これにより、画面遷移でも View と ViewModel 間の疎結合を維持しています。

社員情報編集画面の XAML です。InteractionMessageTrigger で ViewModel からの画面終了メッセージを受信します。


以上、簡単なサンプルですが、Livet による画面遷移の実装上のポイントは抑えられていると思います。何かの参考になれば幸いです。


「いつものパン」があなたを殺す: 脳を一生、老化させない食事 (単行本)

「いつものパン」があなたを殺す: 脳を一生、老化させない食事 (単行本)