4
3

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 1 year has passed since last update.

WPFでMaterialDesign導入したからMessageBoxもおしゃれにしたい!

Last updated at Posted at 2021-11-29

2022/04/13 改良版記事を作成しました。

はじめに 

WPFでMaterialDesignThemes導入してせっかく見た目をかっこよくしても、
MessageBoxを表示させてみたら標準のままでダサかった…。

MaterialDesignThemesでダイアログを出す方法はなんとなくわかったけど、
標準のMessageBoxライクに簡単に表示させたい。

こちらは、そんな方に向けた記事です。

環境

  • .NET 5.0
  • C#
  • Prism.Unity
  • MaterialDesignThemes

ダイアログView

まずはUserControlとして、さくっとダイアログ本体となるものを用意します。
これさえ作っちゃえば、あとはサクサクッとできちゃいます。

MyMessageBox.xaml
<UserControl
    x:Class="TestApp.Views.MyMessageBox"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d">
    <Grid Margin="16">
        <Grid.RowDefinitions>
            <RowDefinition />
            <RowDefinition />
        </Grid.RowDefinitions>
        <StackPanel Grid.Row="0" Orientation="Vertical">
            <TextBlock
                FontSize="20"
                FontWeight="Bold"
                Style="{StaticResource MaterialDesignBody1TextBlock}"
                Text="{Binding DialogTitle}" />
            <TextBlock
                FontSize="16"
                FontWeight="Medium"
                Style="{StaticResource MaterialDesignBody1TextBlock}"
                Text="{Binding DialogText}" />
        </StackPanel>
        <StackPanel
            Grid.Row="1"
            Margin="0,16,0,0"
            HorizontalAlignment="Right"
            Orientation="Horizontal">
            <Button
                Command="{x:Static materialDesign:DialogHost.CloseDialogCommand}"
                CommandParameter="キャンセル"
                Content="キャンセル"
                IsCancel="True"
                Style="{StaticResource MaterialDesignFlatButton}" />
            <Button
                Margin="8,0,0,0"
                Command="{x:Static materialDesign:DialogHost.CloseDialogCommand}"
                CommandParameter="OK"
                Content="OK"
                IsDefault="True"
                Style="{StaticResource MaterialDesignFlatButton}" />
        </StackPanel>
    </Grid>
</UserControl>

縦並びのダイアログのタイトル・テキストエリア、
横並びのキャンセル・OKボタンエリアに分かれてます。

文字の大きさやボタンの配置などは以下を参考に。

CommandParameterはダイアログのボタンを押したときに返ってくる値ですね。
文字列じゃなくても、boolにしたり、intにしたり、お好きなように。

ダイアログを表示させるViewとViewModel

ManWindow.xaml
<Window
    x:Class="TestApp.Views.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
    xmlns:prism="http://prismlibrary.com/"
    Title="{Binding Title}"
    Width="525"
    Height="350"
    prism:ViewModelLocator.AutoWireViewModel="True">
    <materialDesign:DialogHost CloseOnClickAway="True" DialogTheme="Inherit">
        <Grid>
            <Button
                Width="100"
                Command="{Binding ClickCommand}"
                Content="ボタン"
                Style="{StaticResource MaterialDesignRaisedButton}" />
        </Grid>
    </materialDesign:DialogHost>
</Window>

DialogHostで囲んだ部分を覆うようにダイアログのグレー背景、ダイアログが表示されるようになります。
なので画面全体に対して表示させたい場合は上記のようにします。
CloseOnClickAwayプロパティはダイアログの外側をクリックで閉じられるようにするかどうかのプロパティです。

あとはボタン等のコントロールにCommandを設定してやり、ViewModelで呼ぶだけ。

MainWindowViewModel.cs
using MaterialDesignThemes.Wpf;
using Prism.Commands;
using Prism.Mvvm;
using System.Diagnostics;
using TestApp.Views;

namespace TestApp.ViewModels
{
    public class MainWindowViewModel : BindableBase
    {
        public MainWindowViewModel()
        {

        }

        // プロパティ
        private string _title = "MessageBoxApplication";
        public string Title
        {
            get { return _title; }
            set { SetProperty(ref _title, value); }
        }

        private string _dialogTitle;
        public string DialogTitle
        {
            get { return _dialogTitle; }
            set { SetProperty(ref _dialogTitle, value); }
        }

        private string _dialogText;
        public string DialogText
        {
            get { return _dialogText; }
            set { SetProperty(ref _dialogText, value); }
        }

        // コマンド
        private DelegateCommand<string> _clickCommand;
        public DelegateCommand<string> ClickCommand =>
            _clickCommand ?? (_clickCommand = new DelegateCommand<string>(ExecuteCommandName));

        // コマンド実行メソッド
        private async void ExecuteCommandName(string parameter)
        {
            DialogTitle = "確認";
            DialogText = "ダイアログの説明文です。よろしいですか?";
            var result = await DialogHost.Show(new MyMessageBox());

            if ((string)result == "OK")
            {
                Debug.Print("OKが押されました。");
            }
            else if ((string)result == "キャンセル")
            {
                Debug.Print("キャンセルが押されました。");
            }
            else
            {
                Debug.Print("ダイアログの外が押されました。");
            }
        }
    }
}

ダイアログのタイトル・テキスト設定する部分が不格好なので改善の余地ありですが…。
とりあえず
var result = await DialogHost.Show(new MyMessageBox());
で標準のMessageBox.Showライクにダイアログが出せるようになります。

image.png
image.png

最後に

MaterialDesignThemesでのダイアログの出し方はほかにもいくつかありますが、
自分はこの形が一番しっくりきました。
Viewだけでもできるけど、Viewのコード量が増えるのが微妙だったり…。
やりやすい方法はいろいろ探せば出てくると思うので、この記事は参考程度で、自分に合ったやり方を見つけるのがいいと思います!

参考サイト

4
3
0

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
4
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?