はじめに
オレオレ解釈の覚え書き その7
引き続き相互作用処理についての内容で、Prism 7.2 から採用された DialogService を使ったダイアログ表示の実装方法をまとめます。なお、本稿の例では Prism のほか Unity DI コンテナも利用しています。(DI コンテナについての説明はここでは割愛します。)
※相互作用処理とは何かについては前回の記事にまとめました。
本文
はじめに、表示するダイアログの View と ViewModel を用意しましょう。View は UserControl として生成し、対応する ViewModel は IDialogAware インターフェースを実装しておきます。
<UserControl x:Class="TestApp.Views.Dialogs.MessageDialog"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:i="http://schemas.microsoft.com/xaml/behaviors"
xmlns:p="http://prismlibrary.com/"
p:ViewModelLocator.AutoWireViewModel="True">
<Grid Margin="20 10 20 15">
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="10"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<TextBlock Grid.Row="0" Text="{Binding Message, Mode=OneWay}"/>
<Button Grid.Row="2" Content="OK" Command="{Binding OKCommand, Mode=OneTime}" HorizontalAlignment="Right"/>
</Grid>
</UserControl>
namespace TestApp.ViewModels.Dialogs
{
public class MessageDialogViewModel : BindableBase, IDialogAware
{
private string _title;
public string Title
{
get => this._title;
set => this.SetProperty(ref this._title, value);
}
private string _message;
public string Message
{
get => this._message;
set => this.SetProperty(ref this._message, value);
}
public ICommand OKCommand { get; }
public event Action<IDialogResult> RequestClose;
public MessageDialogViewModel()
{
this.OKCommand = new DelegateCommand(() => this.OnRequestClose(new DialogResult(ButtonResult.OK)));
}
public void OnDialogOpened(IDialogParameters parameters)
{
this.Title = parameters.GetValue<string>(nameof(this.Title)) ?? string.Empty;
this.Message = parameters.GetValue<string>(nameof(this.Message)) ?? string.Empty;
}
public bool CanCloseDialog()
{
return true;
}
public void OnDialogClosed()
{
}
protected void OnRequestClose(IDialogResult dialogResult)
{
this.RequestClose?.Invoke(dialogResult);
}
}
}
上記で定義したダイアログの View と ViewModel の型をアプリケーションのエントリーポイントで DI コンテナに登録します。これにより、後述する IDialogService インターフェースを経由して登録されたダイアログを利用できます。
namespace TestApp
{
public partial class App : PrismApplication
{
protected override void RegisterTypes(IContainerRegistry containerRegistry)
{
containerRegistry.RegisterDialog<Views.Dialogs.MessageDialog, ViewModels.Dialogs.MessageDialogViewModel>();
}
}
}
ダイアログを表示するクラスでは、IDialogService.ShowDialog メソッドを使用し、指定されたクラス名のダイアログを表示することができます。(例では示されていませんが、戻り値を受け取ることも可能です。)
namespace TestApp.ViewModels
{
public class MainWindowViewModel
{
[Dependency]
public IDialogService DialogService { get; set; }
// このメソッドを呼び出せばダイアログを表示できる
public void ShowMessage()
{
var parameters = new DialogParameters {
{ nameof(MessageDialogViewModel.Title), "タイトル" },
{ nameof(MessageDialogViewModel.Message), "メッセージ" },
};
this.DialogService.ShowDialog("MessageDialog", parameters, null);
}
}
}
IDialogService という明らかにダイアログ表示を意識したインターフェースが ViewModel に登場するのは少々気持ち悪いですが、実体は外部から注入されており、依存関係の排除とテスタビリティの高さを兼ね備えています。また InteractionRequest とは違い View にトリガーを定義する必要がないため、ViewModel 内で処理が完結しています。
おわりに
DialogService を使った相互作用処理についてまとめました。比較的新しい機能で情報は少ないですが、ダイアログを表示する手段がまた一つ増えました。
一方で InteractionRequest は汎用性が高く、ViewModel を起点に何かを発信する用途であれば、ダイアログの表示以外にも様々な用途が考えられます。これらもまた適材適所で使い分けていくことになりそうです。
Prism 7.2 で Obsolete が付与された InteractionRequest は次期バージョンで削除されることになりました。現在使用中の Prism をアップデートする場合はご注意ください。
次回は View からの処理依頼を受け取る委譲コマンドについてまとめます。