2
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

MVVMとダイアログ

Last updated at Posted at 2021-08-22

MVVMとNavigationの続きです.
ナビゲーションではなくダイアログを表示するには。

基本的なアイデア

基本的にDIとMessengerを使うだけで、やることは初歩的なダイアログ表示方法と同じです。
※MVVMフレームワークとしてMicrosoft.Toolkit.Mvvmを前提としたサンプルコードを記載しています。

ViewとViewModelの関連付け

今回動的に解決されるのはViewのほうなのでViewLocatorクラスを作ります。シンプルに対応をマッピングします。DIコンテナとかを内部でラップしてもいいでしょう。Appクラスのスタートアップ等でマッピングを実装します。

ViewLocator.cs
    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にアタッチしておきます。

ShowDialogBehavior.cs
    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を設定するかとか、モーダルかモードレスかといったオプションを含めると思います。

ShowDialogMessage.cs
    class ShowDialogMessage
    {
        public object ViewModel { get; set; }
    }

ViewModelの実装

ViewModelを生成し、Messageに格納し、Messengerに渡します。シンプルにnewしていますが、ここでDI等を使うのは簡単です。

MainWindowViewModel.cs
        private void ShowDialogCommandExecute()
        {
            var viewModel = new DialogWindowViewModel();
            WeakReferenceMessenger.Default.Send(new ShowDialogMessage { ViewModel = viewModel });
            this.DialogResult = viewModel.Input;
        }

このロジックを基底クラスに定義したり、DIでサービスを受け取ってそのメソッドを実行したりするようにすれば再利用も簡単になります。

まとめ

DataTemplateを使ってデータ駆動ナビゲーションをした前回の記事に比べ、ただMessengerでダイアログを出すだけになりました。
結局Prismとどちらがいいかというと…
コードはこちら

2
4
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?