PrismのIDialogServiceを試してみる

2019/11/29

C# Prism

アイキャッチ

この記事は2019年11月に書きましたが、自分的にはあまり使用頻度が高くなさそうだったので相当手抜きでサンプルソースの紹介だけでした。

しかしアクセス回数が多く、せっかく来て頂いたのに手抜き記事では申し訳ありませんでの2021年10月にきちんと書き直してみました。

尚、この記事を書いた当時のPrismはバージョン7でしたが現在はバージジョン8であり、もしかしたら機能がアップしているかもしれませんので分かったら随時追記したいと思います。

サンプルは

App.xaml.cs

デフォルトで存在しているRegisterTypesメソッドにRegisterDialogメソッドを使ってダイアログを追加します。

今回表示するViewは「Dialog.xaml」としViewModelは「DialogViewModel.cs」としてPrism UserControl(WPF)を追加しました。

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

ダイアログを登録するRegisterDialogメソッドは上記コードのように登録時にViewとViewModelを記述する手法とViewのみ記述する手法の2つの手段があります。

今回のケースではViewのみで問題なく実行できます。

MainWindowViewModel.csのコンストラクタ

宣言している変数は

public ReactiveCommand ShowDialgo { get; } = new ReactiveCommand();
public ReactivePropertySlim<string> DialogValue1 { get; } = new ReactivePropertySlim<string>();
public ReactivePropertySlim<int> DialogValue2 { get; } = new ReactivePropertySlim<int>();
private readonly IDialogService dlgService;

各変数の説明は

ShowDialgoMainWindow.xamlにあるボタンのCommandにバインディングする変数

DialogValue1ダイアログの戻り値で名称がkey1の値を入れMainWindow.xamlに表示する情報

DialogValue2ダイアログの戻り値で名称がkey2の値を入れMainWindow.xamlに表示する情報

dlgServiceコンストラクタの引数IDialogServiceで取得したIDialogService型の情報

コンストラクタの中身は以下となります。

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

4行目でコンストラクタ引数で得たdialogServiceを別メソッドでも使えるようprivate readonlyな変数に入れています。

6行目からはボタンの押された処理になります。

8行目で実際にダイアログを表示するshowDialogメソッドを実行していますが、別メソッドではなくベタに書いてもかまいませんが今回は分けて説明するためにメソッドとしています。

10行目でダイアログが返したResultがButtonResultのどれなのかを見て処理を変えてます。

ダイアログから返ってきたIDialogParametersはIDialogResultのParameters.GetValueメソッドで取得できますが、取得するキー名が間違っているとnullが返ってくるので注意が必要です。

またダイアログからのDialogResultはButtonResultを返さない事もできますのでこれも間違えないようにしなくてはいけません。

MainWindowViewModelからダイアログを表示する

サンプルコードの自作メソットshowDialogが実際のダイアログを表示する部分になります。

private IDialogResult showDialog(string message1, int message2)
{
    IDialogResult result = null;
    // パラメータを渡す手法その1
    //IDialogParameters parameters = new DialogParameters { { "Message1", message1 }, { "Message2", message2 } };
    // パラメータを渡す手法その2
    IDialogParameters parameters = new DialogParameters();
    parameters.Add("Message1", message1);
    parameters.Add("Message2", message2);
    // ShowDialogの引数1:開くダイアログの名称 引数2:ダイアログに渡すパラメータ(KeyとValueのセット)で複数可 引数3:受け取る戻り値
    dlgService.ShowDialog("Dialog", parameters, dialogResult => result = dialogResult);
    return result;
}

ダイアログにわたすパラメータはIDialogParametersに文字列のキー名とobject型の値をセットとします。

2種類の手法を書きましたが個人的には「その2」の方が可読性が良く変更も容易に感じました。

11行目がダイアログを表示させるShowDialogメソッドですが、ここでコンストラクタで取得したIDialogServiceを利用しています。

DialogViewModel.csで必ず必要なもの

これがダイアログのViewModelになります。

注意点としてはIDialogAwareを継承しているので幾つかデフォルトで記述する必要があります。

public string Title => "タイトル";
public event Action<IDialogResult> RequestClose;
public bool CanCloseDialog()
{
    return true;
}
public void OnDialogClosed()
{
    // ウィンドウを閉じる時に返す値をセットする例
    Result.Add("key1", "Value1");
    Result.Add("key2", 100);
    // まどめてDispose
    Disposable.Dispose();
}
public void OnDialogOpened(IDialogParameters parameters)
{
    // 例はダイアログを起動させたViewModelから来たKey「Message1」と「Message2」のValueを取得
    Message1.Value = parameters.GetValue<string>("Message1");
    Message2.Value = parameters.GetValue<int>("Message2");
}

1行目はダイアログに表示される名称です。

変数名は変えないようにしてください。

2行目はダイアログのCloseを要求するActionです。

これも何も変えずに使用します。

3行目からのメソッドはダイアログが閉じれるか判断し閉じれればtrue、まだ閉じれなければfalseを返すプログラムを書いてください。

メソッド名は不変です。

7行目のメソッドはダイアログが閉じられる時に実行されるメソッドです。

サンプルではこのタイミングでメインウインドウに返す値を文字列の「キー名」とobject型の値のペアでAddしていますが、これ以前に返す値をAddしてもOKです。

メソッド名は不変なので注意してください。

何か順番が違いますが定義されている順に説明すると最後に説明するOnDialogOpenedが起動した時に実行されるメソッドです。

15行目からになりますが、これもメソッド名は不変です。

引数IDialogParametersのGetValue<取得する型>("キー名")でメインウインドウから来た値を取得します。

DialogViewModel.csのコンストラクタ

ここではダイアログでボタンが押された処理を明記しています。

public DialogViewModel()
{
    // 「はい」ボタンが押された時はButtonResult.YesとDialogParametersを返す
    _ = YesCommand.Subscribe(_ => RequestClose?.Invoke(new DialogResult(ButtonResult.Yes, Result))).AddTo(Disposable);
    // 「いいえ」ボタンが押された時はButtonResult.Noだけを返す
    _ = NoCommand.Subscribe(_ => RequestClose?.Invoke(new DialogResult(ButtonResult.No))).AddTo(Disposable);
}

「はい」ボタンが押された時のCommandがReactiveCommandのYesCommandになり「いいえ」ボタンが押された時ぼCommandはCommandがReactiveCommandのNoCommandになります。

それぞれのボタンが押された時RequestCloseの引数IDialogResultの内容を変えならが RequestCloseが実行されます。

「はい」ボタンが押された時はButtonResult.Yesと返す値、「いいえ」が押された時はButtonResult.Noだけを返します。

また何も情報を返す必要がない場合は戻り値なしでのDialogResultを返してもOKです。

追記

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

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

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

自己紹介

自分の写真



新潟県のとある企業で働いてます。
【できる事】
電子回路設計
基板パターン設計
マイコンプログラム
C#(WinForms WPF)を使ったWindowsアプリケーション作成
PLCラダー
自動化装置アドバイザー
にほんブログ村 IT技術ブログ ソフトウェアへ

カテゴリ

このブログを検索

QooQ