[WPF][XAML]MahApps.Metroのダイアログを使ってみる


# MahApps.Metroのダイアログを使ってみる

## 開発環境
- Visual Studio 2017 (C#)
- Visual Studioの拡張機能の「Prism Template Pack」
  - Prism.Core 6.3.0
  - Prism.Unity 6.3.0
  - Prism.Wpf 6.3.0
  - CommonServiceLocator 1.3.0
  - Unity 4.0.1
- MahApps.Metro 1.5.0


## 初めに
WPFでシングルページアプリケーションを作成していても、やっぱりダイアログ表示がしたい！って時ありますよね？

でも、入力系のダイアログであれば、個人的には、カスタムダイアログではなく、フライアウトを推奨しますが、処理終了メッセージなんかは、やっぱりダイアログにしたいって時には、MahApps.Metroには、Metro風なダイアログがあるので、それを使ってみてはどうでしょうか？

[MahApps.Metroのダイアログコントロール](http://mahapps.com/controls/dialogs.html)

※MahAppsのプロジェクトへのNuGet追加等の説明は省略

## MahApps.Metro Dialogs
MahApps.Metroには、メッセージダイアログとプログレスダイアログがあります。
使用方法としては、非同期実行できるので`async/await`を付けた上で、それぞれ記述は以下のようになります。

```xml:メッセージダイアログの場合
await this.ShowMessageAsync("This is the title", "Some message");
```

![WS000074.JPG](https://qiita-image-store.s3.amazonaws.com/0/90597/a98ec521-6201-2dbc-fd01-bd3db9129b96.jpeg)


```xml:プログレスダイアログの場合
var controller = await this.ShowProgressAsync("Please wait...", "Progress message");
```

![WS000075.JPG](https://qiita-image-store.s3.amazonaws.com/0/90597/2f1b77d1-a8d8-5c23-ba7c-468110065006.jpeg)


## MVVMではそのままだとエラーになる
コードビハインドでの記述であれば、そのまま使用できますが、
Prism+Unityを使ったようなMVVM複合アプリケーションの場合は、UserControlもしくは、PageのViewModelに処理を記述するため、上記の書き方では、エラーになります。

- エラー画面

![WS000073.JPG](https://qiita-image-store.s3.amazonaws.com/0/90597/4f3abb15-5d38-37d6-0d62-348a9ac4c0e8.jpeg)

これは、MetroWindowの拡張機能で各メッセージダイアログのため、UserControlやPageからではエラーになります。

MVVMの場合は、公式のページでIDialogCoordinatorを使って例が出ています。

> Support for viewmodels
> You can open dialogs from your viewmodel by using the IDialogCoordinator.
> Add the following code to your Window.xaml or UserControl.xaml:


## MVVMの理屈からは崩れちゃうけど

そもそもM+V+VMでは、役割を分けましょうということで直接Viewに対しての指定は行わないのですが、
単純にダイアログは、MetroWindowから呼び出されるので、以下の方法でも表示できます。

- `public MetroWindow Metro { get; set; }`でプロパティを作り、カレントのMetroWindowを格納する
-  `Metro.ShowMessageAsync("This is the title", "Some message");`格納したMetroのShowMessageAsyncを指定する。


```csharp:MainUcViewModel.cs
/// <summary>
/// MetroWindow
/// </summary>
public MetroWindow Metro { get; set; } = System.Windows.Application.Current.MainWindow as MetroWindow;
```

- メッセージダイアログの場合

```csharp:MainUcViewModel.cs
/// <summary>
/// メッセージダイアログ　コマンド
/// </summary>
private DelegateCommand showMessageCommand;
public DelegateCommand ShowMessageCommand =>
    showMessageCommand ?? (showMessageCommand = new DelegateCommand(ShowMessageCommandExecute));

/// <summary>
/// メッセージダイアログ表示処理
/// </summary>
private async void ShowMessageCommandExecute()
{
    await Metro.ShowMessageAsync("This is the title", "Some message");
}
```

- プログレスダイアログの場合


```csharp:MainUcViewModel.cs
/// <summary>
/// プログレスダイアログ　コマンド
/// </summary>
private DelegateCommand showProgressCommand;
public DelegateCommand ShowProgressCommand =>
    showProgressCommand ?? (showProgressCommand = new DelegateCommand(ShowProgressCommandExecute));

/// <summary>
/// プログレスダイアログ表示処理
/// </summary>
private async void ShowProgressCommandExecute()
{
    var controller = await Metro.ShowProgressAsync("Please wait...", "Progress message");

    for (var i = 0; i < 10; i++)
    {
        controller.SetProgress(1.0 / 10 * i);
        await Task.Delay(100);
    }
    await controller.CloseAsync();
}
```

## 実行結果

![MahAppsDialogs.gif](https://qiita-image-store.s3.amazonaws.com/0/90597/80499e49-e9ea-57a8-103f-5222ffb603b6.gif)

## まとめ
MVVM複合アプリケーションでもMahApps.Metroのダイアログを使う場合に、公式にあるように`IDialogCoordinator`を使うのが良いのでしょうが、こんな方法でも一応表示はできます。
Window自体は、特に固定でView名を指定したわけではないので、このぐらいは許容範囲かなと個人的には思います。

 既にQiita内でもViewModelから表示するIDialogCoordinatorを使用した方法を投稿されている方がすでにいらっしゃいました。
soiさんの投稿
> [WPFでいけてるダイアログを出す方法](http://qiita.com/soi/items/e322d60d22af6fcd7da9)

こちらを参考にされたほうが良いかも？

## 補足情報

- 確認メッセージの場合は、以下のようにオプション指定をすることで可能です。

```csharp
/// <summary>
/// メッセージダイアログ表示処理
/// </summary>
private async void ShowMessageCommandExecute()
{
    var metroDialogSettings = new MetroDialogSettings()
    {
        AffirmativeButtonText = "はい",
        NegativeButtonText = "いいえ",
        AnimateHide = true,
        AnimateShow = true,
        ColorScheme = MetroDialogColorScheme.Theme,
    };

    var diagResult = await Metro.ShowMessageAsync("This is the title", "Some message", MessageDialogStyle.AffirmativeAndNegative, metroDialogSettings);
    Console.WriteLine(diagResult);
}
```

![WS000085.JPG](https://qiita-image-store.s3.amazonaws.com/0/90597/7c4aaaee-084e-d045-e851-532df413ee13.jpeg)