読者です 読者をやめる 読者になる 読者になる

亀岡的プログラマ日記

京都のベッドタウン、亀岡よりだらだらとお送りいたします。

Livetを使ってすっきりWPFアプリを作る ③サンプルプロジェクトからLivetの機能を理解する(メッセージ基本編-その2)

WPF C# Livet

さて、昨日から引き続いてサンプルで使われているMessageの解説です。
まず少しおさらい。サンプルでMVVMerが気になるViewModel→Viewの機能は、

  • 新規登録/編集ウィンドウの表示
  • 消去時のメッセージボックス表示(確認)
  • ウィンドウクローズ

の3つです。このうち新規登録/編集ウィンドウの表示は前回エレガントさを実感できたと思います。

メッセージボックス表示処理はどこ????

常識で考えると、コマンド発行後に入ることになりますので、ViewModel側にあるはずです。んじゃあ消去するコマンドを見てみましょう・・・、あったあった、MainViewModel.RemoveCommandですね。ちと長くなりますが全体を。

        #region RemoveCommand
        ListenerCommand<ConfirmationMessage> _RemoveCommand;

        public ListenerCommand<ConfirmationMessage> RemoveCommand
        {
            get
            {
                if (_RemoveCommand == null)
                    _RemoveCommand = new ListenerCommand<ConfirmationMessage>(Remove, CanRemove);
                return _RemoveCommand;
            }
        }

        private bool CanRemove()
        {
            return CheckedViewModel.Any();
        }

        private void Remove(ConfirmationMessage message)
        {
            if (message.Response.HasValue && message.Response.Value)
            {
                CheckedViewModel.ToList().ForEach(m => m.RemoveCommand.Execute());
            }
        }
        #endregion

あれれ、Message.Raiseがありませんよ・・・?

ちょっと気になるのが、ConfirmationMessageというのですね。ConfirmationMessageというのにResponseというプロパティがあり、これのbool値によって実行の制御をしているようです。そしてConfirmationMessageはLivetの組み込みクラスです。

それではView側でConfirmationMessageを使ってる部分を探してみましょう。検索ボタンをポチッとな。

            <Button Grid.Column="3" Content="削除" IsEnabled="{Binding RemoveCommand.CanExecute}">
                <i:Interaction.Triggers>
                    <i:EventTrigger EventName="Click">
                        <l:ConfirmationDialogInteractionMessageAction>
                            <!--
                            DirectInteractionMessageのCallbackCommandプロパティにコマンドを設定する事で
                            Viewで生成したメッセージを元にアクション実行後、コマンドを実行させる事ができます。
                            その場合、コマンドには引数としてメッセージが渡ります
                            -->
                            <l:DirectInteractionMessage CallbackCommand="{Binding RemoveCommand}">
                                <l:ConfirmationMessage Button="OKCancel" 
                                                  Caption="確認"
                                                  Text="本当にチェックの付けられたメンバー情報を削除しますか?"
                                                  Image="Information"/>
                            </l:DirectInteractionMessage>
                        </l:ConfirmationDialogInteractionMessageAction>
                    </i:EventTrigger>
                </i:Interaction.Triggers>
            </Button>

おお、ちゃんとコメントがありますね。

DirectInteractionMessageのCallbackCommandプロパティにコマンドを設定する事でViewで生成したメッセージを元にアクション実行後、コマンドを実行させる事ができます。その場合、コマンドには引数としてメッセージが渡ります。

なるほど、DirectInteractionMessageを用いることで、任意のメッセージを実行後にコマンドを実行させることができるわけですね。サンプルではLivet組み込みのConfirmInteractionMesssageというのを使っていますが、これはこっちでカスタムメッセージを作ればかなり柔軟な事ができそうです。
さて、ConfirmInteractionMessageですが、Confirm形式のメッセージボックス(Yes/Noがでるやつ)を作成してくれる感じですね。Button、Caption、Text、Imageとお馴染みのプロパティが並んでいます。

この流れを見てわかるのは、LivetではちゃんとViewModelで意識することなく、Viewのみで完結した形でメッサーじボックス(カスタムすれば他のモーダルダイアログの表示も)できるわけです。前回ちょっと書いたように、本来こういった処理はViewの責務で行うべきだと考えているので、こんな書き方ができるのは非常に大きな驚きです。

最後にウィンドウ終了のメッセージです。これは本当にViewModel内には影も形も有りません。XAML内に以下のような記述があるばかりです。

            <Button Grid.Column="4" Content="終了">
                <i:Interaction.Triggers>
                    <i:EventTrigger EventName="Click">
                        <l:WindowInteractionMessageAction>
                            <l:DirectInteractionMessage>
                                <l:WindowActionMessage Action="Close"/>
                            </l:DirectInteractionMessage>
                        </l:WindowInteractionMessageAction>
                    </i:EventTrigger>
                </i:Interaction.Triggers>
            </Button>

イベントトリガー経由でWindowActionMessageというアクションを実行してます。Actionには他にもActive・Close・Minimizeと一通りそろっていますね。
ちなみにこの部分の上には作者さんのドヤ顔が透けて見えるこんなメッセージが書いてあります。

ViewModelを経由せずにメッセージを生成し、Windowを閉じています。Livetでは、ViewModelを経由する必要のない相互作用をこの様にView内で完結させられます。

このメッセージ部分、Livetの紹介パワポでもおまけ機能程度の扱いでしか触れられていないのですが、個人的にはLivetを他のMVVMライブラリから大きく差別化している要因だと思います。コードビハインドを取り去り、責務をView内できっちり完結させるという思想は、一度WPF/MVVMで痛い目を見た僕にとっては非常に理想的な思想であり、設計制限事項かなあ、と感じています。
というわけで、一旦サンプルを見終わったあとは、このあたりを徹底的に解説していきたいと思います。


とか言ってる間に公式ドキュメントが出てきたらどうしよう・・・