MVVMとNavigationの続きです.
ナビゲーションではなくダイアログを表示するには。
基本的なアイデア
基本的にDIとMessengerを使うだけで、やることは初歩的なダイアログ表示方法と同じです。
※MVVMフレームワークとしてMicrosoft.Toolkit.Mvvmを前提としたサンプルコードを記載しています。
ViewとViewModelの関連付け
今回動的に解決されるのはViewのほうなのでViewLocatorクラスを作ります。シンプルに対応をマッピングします。DIコンテナとかを内部でラップしてもいいでしょう。Appクラスのスタートアップ等でマッピングを実装します。
class ViewLocator
{
public static ViewLocator Default { get; } = new ViewLocator();
private Dictionary<Type, Type> locator = new Dictionary<Type, Type>();
public void Register<TViewModel, TView>() where TView : Window
{
this.locator.Add(typeof(TViewModel), typeof(TView));
}
public Window Locate(Type viewModelType)
{
var winType = this.locator[viewModelType];
return (Window)Activator.CreateInstance(winType);
}
}
Viewロジック
ダイアログ表示は最終的にViewのメソッドになるのでBehaviorを追加します。MessegerからMessageを受け取り、ViewModelの型からViewを特定・生成し、ダイアログを表示するシンプルな内容。ViewModelの相互作用としてダイアログ表示を書いているので、Messageの中にViewModelが含まれます。
コードは省略しますがWindowにアタッチしておきます。
class ShowDialogBehavior : Behavior<Window>
{
protected override void OnAttached()
{
base.OnAttached();
WeakReferenceMessenger.Default.Register<ShowDialogMessage>(this, showDialog);
}
private static void showDialog(object recipient, ShowDialogMessage message)
{
var behavior = (ShowDialogBehavior)recipient;
var dialog = ViewLocator.Default.Locate(message.ViewModel.GetType());
dialog.DataContext = message.ViewModel;
dialog.Owner = behavior.AssociatedObject;
dialog.ShowDialog();
}
}
Messageの実装
Messengerで渡すMessageです。先述の通りViewModelを含みます。今回はこれだけですが、実用的にはOwnerを設定するかとか、モーダルかモードレスかといったオプションを含めると思います。
class ShowDialogMessage
{
public object ViewModel { get; set; }
}
ViewModelの実装
ViewModelを生成し、Messageに格納し、Messengerに渡します。シンプルにnewしていますが、ここでDI等を使うのは簡単です。
private void ShowDialogCommandExecute()
{
var viewModel = new DialogWindowViewModel();
WeakReferenceMessenger.Default.Send(new ShowDialogMessage { ViewModel = viewModel });
this.DialogResult = viewModel.Input;
}
このロジックを基底クラスに定義したり、DIでサービスを受け取ってそのメソッドを実行したりするようにすれば再利用も簡単になります。
まとめ
DataTemplateを使ってデータ駆動ナビゲーションをした前回の記事に比べ、ただMessengerでダイアログを出すだけになりました。
結局Prismとどちらがいいかというと…
コードはこちら