2011年05月22日

MVVM:Messenger + Behaviorを理解するために自作してみた(3)

   このエントリーをはてなブックマークに追加 Clip to Evernote
MVVM:Messengerを理解するために自作してみた(1)
MVVM:Messengerを理解するために自作してみた(2)
MVVM:Messengerを理解するために自作してみた(3)
MVVM:Messenger + Behaviorを理解するために自作してみた(1)
MVVM:Messenger + Behaviorを理解するために自作してみた(2)

これまでは、Messengerオブジェクトを利用するときには、Defaultプロパティを使用していましたが、
いわゆるシングルトンオブジェクトと同じなので、ひとつのMessengerオブジェクトが、いくつものViewと
ViewModelの仲介をすることになります。

これだと、不都合な状況というのが生まれる可能性があります。
例えば、複数のViewが同時に表示されている場合を考えると、あるViewModelから、特定のViewにメッセージを
送りたいのに、ほかのViewにもメッセージが送られてしまうことになります。

シングルトンオブジェクトを止めて、ViewModel毎に、Messengerが生成すればいいのですが、
どうやって、このMessengerオブジェクトをビヘイビアで参照したら良いのかが問題になります。

これを解決するのが、データバインドの機能です。
XAMLのビヘイビアを記述する時に、データバインドで、Messengerオブジェクトとビヘイビアを
関連付けてあげればよいのです。

どういったXAMLになるのかは、後で説明するとして、まずは、ViewModelの変更からお見せします。


Messengerプロパティを追加し、コンストラクタで、Messengerのインスタンスを生成し、
このプロパティにセットしています。
HelloAction メソッドでは、Messenger.Default.Send ではなく、Messengerプロパティ経由で、
Sendメソッドを呼び出していいます。

では、XAMLの例をお見せします。


バインドさせているのは次に示す行です。


この Messengerは、ViewModel に定義したプロパティの名前となります。
このSourceObjectは、my:ActionCollection 配下の、各Actionで共有されます。

つまり、この例だと、

DialogBoxMessageというメッセージが、SourceObjectで指定した Messenger から送られてきたら、
DialogBoxActionを起動する

ということになります。

これを実現するには、さらにいくつかのクラスを、変更する必要があります。

まずは、IVewActionインターフェースと、その具象クラスです。


Messenger.Defaultというグローバルなオブジェクトではなく、引数で渡されたMessengerに、
メッセージとその対応する処理を登録するようにしています。

つぎに、ActionCollection クラスです。ここに SourceObject プロパティを追加するために、
継承元をCollection から Freezable に変更しました。
その関係で、Collection もプロパティとして保持するように変更しています。


MessengerBehavior も変更します。ここは、変更が必要無いかなと思ったのですが、
RegisterAll メソッドを呼び出すタイミングを変更する必要があったので、以下のように
変更しました。


Loadedイベントで、RegisterAllメソッドを呼ぶように変更しています。
これで、完成です。

これまでに掲載したコード(過去の一連の記事も含む)をコピーし、ひとつのプロジェクトとすれば
正しくビルドできると思います。興味のある方は、是非、実際に動かしてみることを
お勧めします。

ちなみに、Messengerクラスそのものの変更はしていないので、Defaultプロパティを使った方法でも
コーディング可能です。

ところで、OnActionsPropertyChanged って,このサンプルコードだと2回呼ばれるんですよね。
なんで、1回じゃないんだろう。


この記事へのコメント
メッセンジャー+ビヘイビアーの複数に配達される問題は、ViewModelのインスタンスをTokenに設定することで解決します。
ビヘイビアーはAssociatedObjectを使ってDataContextからViewModelを取得できます。
Posted by えムナウ at 2011年05月29日 19:55
なるほど、Token を付加することで、識別できるようになるんですね。
情報ありがとうございます。

僕が書いたのは、そこまでは実装していません。
Posted by Gushwell at 2011年05月29日 20:10
 

この記事へのトラックバックURL

http://trackback.blogsys.jp/livedoor/gushwell/52152996