なべひろBlog

プログラミングをメインに仕事に関するアレコレを発信しています。

PrismのIDialogServiceを試してみる

MVVMなWPFでダイアログを出して見るべく色々検索してましたが、正直いって「何か面倒じゃね?」ってのが素直な感想でした。

もしかしたらダイアログを出す以外のコードが多くて、ぱっと見で私がきちんと見てないだけだったかもしれませんがWinFormsと比べるとねぇ。

とは言え、何かマスターしないと後々困るので、一番シンプルそうな手法で試して実験してみました。

使ってみたのはPrismのIDialogServiceです。

コード量もそんなに多くなく、メインウィンドウとダイアログ間で柔軟に多くのデータやり取りも可能という優れ物です。

App.xaml.csに追加

標準でApp.xaml.csにはprotected override void RegisterTypesメソッドがありますのでメソッド内にダイアログのViewModelの数だけ「containerRegistry.RegisterDialog」を追記します。

protected override void RegisterTypes(IContainerRegistry containerRegistry)
{
    // ダイアログ表示時に追加される
    containerRegistry.RegisterDialog<Views.Dialog, ViewModels.DialogViewModel>();
}
ダイアログを開くメソッド

MainWindowViewModel.csに実際のダイアログを開くメソッドを用意します。

サンプルでは引数としてstring型とint型のデータを取得し、その2つのデータを表示するダイアログに渡します。

そしてダイアログからの戻り値IDialogResultをメソッドの戻り値とします。

private IDialogResult showDialog(string message1, int message2)
{
    IDialogResult result = null;
    // ShowDialogの引数1:開くダイアログの名称 引数2:ダイアログに渡すパラメータ(KeyとValueのセット)で複数可 引数3:受け取る戻り値
    this.dlgService.ShowDialog("Dialog", new DialogParameters { { "Message1", message1 }, { "Message2", message2 } }, ret => result = ret);
    return result;
}
共通で使用する変数とコンストラクタ

コンストラクタには引数IDialogServiceがあり上記メソッドで使用するので他のメソッドで使えるようにします。

private readonly IDialogService dlgService;

コンストラクタにはボタンが押された時に実行する内容を記述しておきます。

public MainWindowViewModel(IDialogService dialogService)
{
    // IDialogServiceの情報を取得
    this.dlgService = dialogService;
    // Subscribeにダイアログ表示メソッドを設定し、戻り値の処理を行う
    _ = ShowDialgo.Subscribe(_ =>
    {
        DialogResult = showDialog("メインウィンドウからのメッセージ1", 2);
        // ButtonResultがYesならKey名「key1」の値を取得する。間違ったkey名だとNullを返すので注意が必要。
        DialogValue1.Value = DialogResult.Result == ButtonResult.Yes ? $"Key1の値:{DialogResult.Parameters.GetValue<string>("key1")}" : "いいえが押されました";
        // ButtonResultがYesならKey名「key2」の値を取得する。間違ったkey名だとNullを返すので注意が必要。
        DialogValue2.Value = DialogResult.Result == ButtonResult.Yes ? $"Key2の値:{DialogResult.Parameters.GetValue<string>("key2")}" : "いいえが押されました";
    }).AddTo(Disposable);
}
ダイアログ側の処理

メインウインドウからのメッセージを取得するためダイアログが開いた時のイベントハンドラで取得します。

public void OnDialogOpened(IDialogParameters parameters)
{
    // 例はダイアログを起動させたViewModelから来たKey「Message1」のValueを取得
    this.Message1.Value = parameters.GetValue("Message1");
    this.Message2.Value = parameters.GetValue("Message2");
}

サンプルプログラムではダイアログからメインウインドウに渡すDialogParametersを用意しておいて値を入れています。

public DialogParameters Result { get; } = new DialogParameters();

サンプルプログラムのコンストラクタでは押されたボタンがによってButtonResultの値を変え、状況によっては上記DialogParametersと一緒に返す記述をSubscribeで行ってます。。

public DialogViewModel()
{
    // 「はい」ボタンが押された時はButtonResult.YesとDialogParametersを返す
    this.YesCommand.Subscribe(_ => this.RequestClose?.Invoke(new DialogResult(ButtonResult.Yes, Result))).AddTo(Disposable);
    // 「いいえ」ボタンが押された時はButtonResult.Noだけを返す
    this.NoCommand.Subscribe(_ => this.RequestClose?.Invoke(new DialogResult(ButtonResult.No))).AddTo(Disposable);
    // ウィンドウを閉じる時に返す値をセットする例
    Result.Add("key1", "Value1");
    Result.Add("key2", 100);
}
追記

自分で記事書いておきながらハマったので追記です。

追加するダイアログはソリューションエクスプローラーで「追加」-「新しい項目」の「Prism」-「WPF」にあるPrism UserControl(WPF)です。

Prism Window(WPF)ではないので注意してください。

Prism関連記事

MVVMなWPFアプリケーションでバーコードリーダーの情報をキャッチする。

MVVMなWPFアプリケーションでドラッグ&ドロップをしてみる

Prismを使ったWPFアプリケーションで多重起動を抑制する

Prism使ったWPFでLivetCask.Messagingを使ってみる

Prismで複数のページを持ったアプリを作ってみる

PrismのUserControlを動的に配置する