WPF Prism episode: 17 ~ IDialogService にコモンダイアログを求めるのは間違っているだろうか ~

← 前回記事【WPF Prism episode: 16 ~ Prism7.2、ダイアログは IDialogService でって言ったよね! ~】

再開した前回は Prism 7.2 から追加された IDialogService を利用してメッセージボックスを表示する方法を紹介しました。
今回は前回の補足として IDialogService で表示したダイアログからパラメータを受け取る方法と、Prism 7.2 でコモンダイアログを表示する方法を紹介します。

尚、この記事は Visual Studio 2019 Community Edition で .NET Framework 4.8 以上 と C# + Prism 7.2 + ReactiveProperty を使用して 、WPF アプリケーションを MVVM パターンで作成するのが目的で、C# での基本的なコーディング知識を持っている人が対象です。

IDialogService で表示したダイアログからダイアログ(メッセージボックス)を開く

episode: 16 のおさらいを兼ねて IDialogService で表示したダイアログウィンドウからメッセージボックス(ダイアログウィンドウ)を開く方法を紹介します。
表示するダイアログは episode: 14 で作成した BLEACH のキャラクターを選択するダイアログを流用します。

episod: 14 のソリューションから View をコピーして IDialogAware を実装する必要はありますが、大した修正も無くほとんどそのまま動作します。
src. 1 は IDialogAware を実装したダイアログからメッセージボックスを表示するサンプルです。

episode: 16 で紹介した方法と同じくコンストラクタにインジェクションされる IDialogService からメッセージボックスを表示できるので、Window・UserControl どちらの VM の場合でも統一された方法でメッセージボックスやダイアログウィンドウを扱うことができます

Prism 7.1 までの INotification + IInteractionRequest でもダイアログからメッセージボックスやダイアログウィンドウを開くことはできると思いますが、XAML への記述が不要になった分、簡単でシンプルになったと言えます。

ダイアログウィンドウの Close を中止する

又、src. 1 のように IDialogAware.CanCloseDialog メソッド(イベント)でメッセージボックスを表示すると fig. 1 のようにダイアログウィンドウの Close をキャンセルすることができるようになりました

fig.1 ダイアログウィンドウ Close のキャンセル

MVVM で Window Close をキャンセルする方法は今まで「これだっ!」的な方法を見た覚えが無いので、フレームワーク側で対応してくれたのは嬉しい限りです。

管理人の希望としてはダイアログウィンドウだけでなく Shell(MainWindow)にも Window Close のキャンセルを搭載して欲しいですが、残念ながら Shell には独自で実装するしかないようです。

OnDialogClosed でオブジェクトを後始末する

IDialogAware には CanCloseDialog(Closing イベント) だけでなく OnDialogClosed(Closed イベント)も定義されているので、ReactiveProperty のような Dispose したいオブジェクトの後始末を src. 1 の 29 ~ 30行目のように呼び出せるようになった事もメリットの 1 つだと思います。

ダイアログウィンドウからパラメータを受け取る

src. 1 で IDialogAware を実装したダイアログから呼出元へパラメータを返すには src. 2 のように OK ボタンの Command をバインドした okButton_Click メソッド内で RequestClose.Invoke のパラメータに設定することで可能になります。

episode: 16 で紹介したように、ダイアログに渡すパラメータが文字列のみであれば DialogParameters クラスのコンストラクタを【new DialogParameters($”Message={message}”);】のように記述するだけで済みますが、文字列以外のパラメータを受け渡しする場合には 26 ~ 27 行目のように DialogParameters を new して Add する必要があります。

パラメータの受け取り側は src. 3・26 行目のようにパラメータ設定時に指定した文字列型のキーを渡す事で受け取ることができます。

又、24 行目の ShowDialog メソッドは、別途作成した IDialogService 用の拡張メソッドです。

IDialogService 呼び出し用の汎用拡張メソッド

Prism の IDialogService は fig. 1 のようなモーダルダイアログだけでなく、モードレスダイアログを表示するインタフェースも兼ねているため戻り値をコーバックで受け取るようになっていますが、ダイアログを表示するならやはり Windows Form でもお馴染みの ShowDialog のように呼び出せるメソッドが使いやすいと思って汎用的に使える ShowDialog 用拡張メソッドを作成しました。

まずは、Prism Module テンプレートから『DialogExtensions』のような名前のプロジェクトを作成して、プロジェクトの既定の名前空間へ fig. 2 のように【Prism.Services.Dialogs】を設定します。
※ テンプレートから作成される View や VM は不要なので削除します。

fig.2 プロジェクトのプロパティ

そして、src. 4 のようなクラスを作成すると、src. 3 の 24 行目のようにダイアログを呼び出せるようになります。

必須ではありませんが、このようなプロジェクトを 1 つ作成しておけばどんなプロジェクトへも使い回しができるので便利だと思います。

Prism でコモンダイアログを表示する

episode: 15 では Prism の IConfirmation を利用してコモンダイアログを表示する方法を紹介しましたが、Prism 7.2 以降から IConfirmation が廃止(非推奨)となり新たに IDialogService が導入されました。

それに併せて IDialogService からコモンダイアログを表示する方法を探すと Prism の GitHub Issues #1666 のやり取りの中で紹介されていました。

gojanpaolo さんが書かれたコードを丸ごと引用したのが src. 5 です。

コモンダイアログの表示に必要な記述は src. 5 が全てですが、episode: 16 のコメントでリクエストも頂いていたので管理人もサンプルを作ってみました。

コモンダイアログ用プロジェクト

まず、コモンダイアログ表示用のプロジェクトをソリューションへ追加します。
追加するのは Prism Module プロジェクトではなく普通のクラスライブラリプロジェクトから作成して fig. 3 のような構成を作成しました。

fig.3 CommonDialogLib プロジェクトの構成

管理人はものぐさなので 1 つのサービスで『ファイルを開くダイアログ』、『ファイルに名前を付けて保存ダイアログ』、『フォルダ選択ダイアログ』の 3 つとも表示するために fig. 3 のような構成にしました。

src. 6 は ICommonDialogService インタフェースと実装クラスの CommonDialogService です。

定義した ICommonDialogService もごくごく普通の C# 製インタフェースで、Prism の IDialogService の継承等も必要ありませんし、Prism を意識する必要は全く無いので好きなように作成できます。
※ 唯一、DIコンテナへの登録が必要であることを除きます

ボリュームもそこそこありますし、回りくどい書き方になっているかもしれませんが 1 度作成しておけば他の WPF プロジェクトへ使い回すことができるので無駄にはならないと思います。

Microsoft.Win32 名前空間のファイルを開く、ファイルに名前を付けて保存ダイアログを表示する

src. 7 は Microsoft.Win32 名前空間配下のファイルを開く、ファイルに名前を付けて保存ダイアログを表示するための FileDialogService です。

多少回りくどい書き方になっていると思いますが、コモンダイアログを ShowDialog して戻り値をパラメータへ再格納しているだけの単純なクラスです。

このサービスを Prism の Module で使用するには src. 8 のように PrismApplication.RegisterTypes メソッドから DI コンテナへ登録することで可能になります。
※ プロジェクトの参照設定も必要です。

コモンダイアログの呼び出しは、src. 9 のようにコンストラクタへインジェクションされた ICommonDialogService の ShowDialog を使用します。

ICommonDialogService は表示するコモンダイアログに対応した Settings クラスを ShowDialog のパラメータにセットする仕様なので、ここでは OpenFileDialogSettings を new しています。
実際に実行すると fig. 4 のようにファイルを開くダイアログが表示されます。

fig.4 ファイルを開くダイアログを表示

ここで紹介したサンプルの構成が絶対的に正しいと言いたい訳ではありません。
コモンダイアログごとにサービスを作成する方が良い場合もあると思いますし、紹介した通りコモンダイアログの ShowDialog メソッドを呼び出しているだけの単純な C# クラスなので、適用するプロジェクトの都合や設計・作成者の好みで自由に作れば良いと思うので、参考の一つとして見てください。

Windows API Code Pack のフォルダ選択ダイアログを表示する

fig. 4 は Microsoft.Win32 名前空間の OpenFileDialog を表示していますが、src. 10 のように Windows API Code Pack に含まれる CommonFileDialog 表示用のサービスを作成すれば Visual Studio 2019 等でフォルダを選択する場合に表示される CommonFileDialog も表示できます

episode: 15 では vsvyatski/Ookii.Dialogs GitHub 版 を使用しましたが、ここでは Windows-API-Code-Pack-1.1 に含まれる CommonFileDialog を表示しています。

実行すると fig. 5 のように Windows API Code Pack 版のフォルダ選択ダイアログが表示できます。

fig.5 フォルダ選択ダイアログを表示

ここで紹介した方法は Prism 7.2 以降限定と言う訳ではなく、Prism 7.1 以前のプロジェクトにも適用できます
episode: 15 で紹介した方法は煩雑なので、ここで紹介した方法を選択する方が良いと思います。

いつもの通り、ここで紹介したサンプルコードは GitHub リポジトリ に上げておきます。

ここ 1 か月半くらい残業・休出続きでなかなか新規エントリを公開できませんでしたが、やっと落ち着いたので又ちょっとづつ公開していきたいと思っています。

一応、次回は extra シリーズとして ReactvieProperty の変更通知を Subscribe する方法を予定しています。

 

【WPF Prism episode: 18 ~ Livet が Prism に「IDisposable 呼び出し用」としてゲッツされた件 ~】次回記事 →

 

 

あわせて読みたい

コメントを残す

メールアドレスが公開されることはありません。

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください

%d人のブロガーが「いいね」をつけました。