8
1

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.

ViewModel と相互作用処理(DialogService)

Last updated at Posted at 2020-05-09

はじめに

オレオレ解釈の覚え書き その7

引き続き相互作用処理についての内容で、Prism 7.2 から採用された DialogService を使ったダイアログ表示の実装方法をまとめます。なお、本稿の例では Prism のほか Unity DI コンテナも利用しています。(DI コンテナについての説明はここでは割愛します。)

※相互作用処理とは何かについては前回の記事にまとめました。

本文

はじめに、表示するダイアログの View と ViewModel を用意しましょう。View は UserControl として生成し、対応する ViewModel は IDialogAware インターフェースを実装しておきます。

View(Dialog)
<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>
ViewModel(Dialog)

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 インターフェースを経由して登録されたダイアログを利用できます。

App
namespace TestApp
{
    public partial class App : PrismApplication
    {
        protected override void RegisterTypes(IContainerRegistry containerRegistry)
        {
            containerRegistry.RegisterDialog<Views.Dialogs.MessageDialog, ViewModels.Dialogs.MessageDialogViewModel>();
        }
    }
}

ダイアログを表示するクラスでは、IDialogService.ShowDialog メソッドを使用し、指定されたクラス名のダイアログを表示することができます。(例では示されていませんが、戻り値を受け取ることも可能です。)

ViewModel(Window)
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 からの処理依頼を受け取る委譲コマンドについてまとめます。

8
1
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
8
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?