【Material Design Toolkit】 Dialog

 Material Design ToolkitのDialogはウインドウ上にダイアログを表示する機能で、表示する内容も自分で作成することから新しいウインドウを表示する感覚に近いと思います。(ファイル選択ダイアログやMessageBoxとは使い方が異なります)
 ダイアログの制御方法は複数の方法が用意されていますので、状況に合わせて一番使いやすい方法を選択してください。

1.イベントを利用する方法
 最初に説明する方法はDialogHostのイベントを利用する方法です。
 このサンプルではダイアログが閉じられた際にイベントでダイアログの戻り値を取得します。
<UserControl x:Class="DialogDemo.Views.Dialog1"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
             xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
             xmlns:system="clr-namespace:System;assembly=mscorlib"
             mc:Ignorable="d" 
             d:DesignHeight="300" d:DesignWidth="300">

    <materialDesign:DialogHost DialogClosing="DialogHost_DialogClosing">
        <materialDesign:DialogHost.DialogContent>
            <StackPanel Margin="10">
                <TextBlock Text="Dialog Sample1"/>
                <TextBlock Text="コードビハインド(DialogClosingイベント)を利用したダイアログ"/>
                <StackPanel Orientation="Horizontal" HorizontalAlignment="Center">
                    <Button Style="{StaticResource MaterialDesignFlatButton}" Margin="5"
                                Content="OK" Command="{x:Static materialDesign:DialogHost.CloseDialogCommand}">
                        <Button.CommandParameter>
                            <system:Boolean>True</system:Boolean>
                        </Button.CommandParameter>
                    </Button>
                    <Button Style="{StaticResource MaterialDesignFlatButton}" Margin="5"
                                Content="Cancel" Command="{x:Static materialDesign:DialogHost.CloseDialogCommand}">
                        <Button.CommandParameter>
                            <system:Boolean>False</system:Boolean>
                        </Button.CommandParameter>
                    </Button>
                </StackPanel>
            </StackPanel>
        </materialDesign:DialogHost.DialogContent>

        <Grid>
            <Grid.RowDefinitions>
                <RowDefinition Height="Auto"/>
                <RowDefinition Height="Auto"/>
                <RowDefinition Height="*"/>
            </Grid.RowDefinitions>
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="Auto"/>
                <ColumnDefinition Width="*"/>
            </Grid.ColumnDefinitions>

            <TextBlock Grid.Row="0" Grid.Column="0" Text="Dialogの戻り値:"/>
            <TextBlock Grid.Row="0" Grid.Column="1" Name="DialogResultText"/>

            <Button Grid.Row="1" Grid.Column="0" Grid.ColumnSpan="2"
                Content="Dialog Open"
                Command="{x:Static materialDesign:DialogHost.OpenDialogCommand}"/>
        </Grid>
    </materialDesign:DialogHost>
</UserControl>
using MaterialDesignThemes.Wpf;
using System.Windows.Controls;

namespace DialogDemo.Views
{
    /// <summary>
    /// Dialog1.xaml の相互作用ロジック
    /// </summary>
    public partial class Dialog1 : UserControl
    {
        public Dialog1()
        {
            InitializeComponent();
        }

        private void DialogHost_DialogClosing(object sender, DialogClosingEventArgs eventArgs)
        {
            DialogResultText.Text = eventArgs.Parameter.ToString();
        }
    }
}
 このコードでは以下の様なダイアログが表示されます。
DialogSample1.png
 ダイアログを表示するためには必ずDialogHostが必要になります。
 DialogHostの位置はどこでもよいですが、この領域内にダイアログが表示されるのであまり狭い場所には設定しない方がよさそうです。
 サンプル1ではDialogHostのDialogClosingイベントを利用してダイアログの戻り値を取得しています。
 表示するダイアログの内容はDialogHost.DialogContentに定義します。
 ダイアログの表示はコマンドを使用して行います。
 ダイアログを表示したい場合はmaterialDesign:DialogHost.OpenDialogCommandを使用します。
 また、ダイアログを閉じたい場合はmaterialDesign:DialogHost.CloseDialogCommandを使用します。
 ダイアログを閉じる際にCommandParameterに値を渡して戻り値を返すこともできます。
 このサンプルの場合はOKボタンを押してダイアログを閉じた場合はTrueが、Cancelボタンを押してダイアログを閉じた場合はFalseが返ってきます。
 このサンプルではbool値を返しましたが他の型(文字列等)を返すこともできます。
 この戻り値はDialogClosingイベントのイベント変数を使って受け取ることができます。
 eventArgs.ParameterにCommandParameterの値が入っているのでキャストして使用してください。

2.OpenDialogCommandの引数に表示するダイアログを指定する方法
 2つ目の方法はダイアログの内容をOpenDialogCommandの引数として渡す方法です。
 1つめの方法ではDialogContentの内容が固定されていましたが、この方法では1つのDialogHostで色々な内容のダイアログを表示することができます。
<UserControl x:Class="DialogDemo.Views.Dialog2"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
             mc:Ignorable="d" 
             d:DesignHeight="300" d:DesignWidth="300">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="*"/>
        </Grid.RowDefinitions>

        <StackPanel Grid.Row="0">
            <TextBlock Text="Dialog Sample2"/>
            <TextBlock Text=""/>
        </StackPanel>

        <materialDesign:DialogHost Grid.Row="1">
            <StackPanel>
                <Button Command="{x:Static materialDesign:DialogHost.OpenDialogCommand}"
                        Margin="10" Content="ダイアログを表示1">
                    <Button.CommandParameter>
                        <StackPanel Margin="10">
                            <TextBlock Text="OpenDialogCommandのCommandParameterによるダイアログ1"/>
                            <Button Content="閉じる"
                                    Style="{StaticResource MaterialDesignFlatButton}"
                                    Command="{x:Static materialDesign:DialogHost.CloseDialogCommand}"/>
                        </StackPanel>
                    </Button.CommandParameter>
                </Button>

                <Button Command="{x:Static materialDesign:DialogHost.OpenDialogCommand}"
                        Margin="10" Content="ダイアログを表示2">
                    <Button.CommandParameter>
                        <StackPanel Margin="10">
                            <TextBlock Text="OpenDialogCommandのCommandParameterによるダイアログ2"/>
                            <Button Content="閉じる"
                                    Style="{StaticResource MaterialDesignFlatButton}"
                                    Command="{x:Static materialDesign:DialogHost.CloseDialogCommand}"/>
                        </StackPanel>
                    </Button.CommandParameter>
                </Button>
            </StackPanel>
        </materialDesign:DialogHost>
    </Grid>
</UserControl>
 このコードでは以下の様なダイアログが表示されます。
DialogSample2.png
 この方法ではDialogHostのDialogContentには何も指定しません。
 かわりにmaterialDesign:DialogHost.OpenDialogCommandのCommandParameterにダイアログコンテンツを指定します。

 上記のサンプルコードではCommandParameter内に直接ダイアログコンテンツを記載しましたが、UserControl等で作成したダイアログを使用することもできます。
 以下のサンプルコードはダイアログをUserControlで作成しておき、ViewModelをバインディングして呼び出すコードです。
 使用しているSampleDialogとSampleDialogViewModelは「3.ViewModelからダイアログ表示を行う方法」で使用するダイアログを流用しています。
<UserControl x:Class="DialogDemo.Views.Dialog5"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
             xmlns:local="clr-namespace:DialogDemo.Views"
             xmlns:v="clr-namespace:DialogDemo.Views"
             xmlns:vm="clr-namespace:DialogDemo.ViewModels"
             mc:Ignorable="d" 
             d:DesignHeight="300" d:DesignWidth="300">
    <UserControl.DataContext>
        <vm:Dialog5ViewModel/>
    </UserControl.DataContext>
    
    <materialDesign:DialogHost>
        <StackPanel>
            <Button Content="ダイアログ表示" DataContext="{Binding ViewModel}"
                    Command="{x:Static materialDesign:DialogHost.OpenDialogCommand}">
                <Button.CommandParameter>
                    <v:SampleDialog/>
                </Button.CommandParameter>
            </Button>

            <Button Content="ダイアログ表示(バインディング失敗)" 
                    Command="{x:Static materialDesign:DialogHost.OpenDialogCommand}">
                <Button.CommandParameter>
                    <v:SampleDialog DataContext="{Binding ViewModel}"/>
                </Button.CommandParameter>
            </Button>
        </StackPanel>
    </materialDesign:DialogHost>
</UserControl>
using Livet;

namespace DialogDemo.ViewModels
{
    public class Dialog5ViewModel : ViewModel
    {
        public Dialog5ViewModel()
        {
            ViewModel = new SampleDialogViewModel();
        }

        #region ViewModel変更通知プロパティ
        private SampleDialogViewModel _ViewModel;

        public SampleDialogViewModel ViewModel
        {
            get
            { return _ViewModel; }
            set
            {
                if (_ViewModel == value)
                    return;
                _ViewModel = value;
                RaisePropertyChanged();
            }
        }
        #endregion
    }
}
 ダイアログの指定方法はDialog Sample2と同じですが、ViewModelをバインディングする場合は少し注意が必要です。
 CommandParameter以下のSampleDialogのDataContentにViewModelをバインディングしてもうまくいきません。
 SampleDialogにViewModelを渡すためにはButtonのDataContentにViewModelをバインディングします。
 実際にダイアログを表示させてみると以下の様になります。
DialogSample5.png

3.ViewModelからダイアログ表示を行う方法
 3つ目の方法はViewModelからダイアログ表示を行う方法です。
 この方法では表示するダイアログをUserControl等で定義しておく必要があります。
 以下のコードがサンプル3で使用するダイアログとそのViewModelです。
<UserControl x:Class="DialogDemo.Views.SampleDialog"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
             xmlns:system="clr-namespace:System;assembly=mscorlib"
             mc:Ignorable="d" 
             d:DesignHeight="300" d:DesignWidth="300">
    <StackPanel Margin="10">
        <TextBlock Text="Dialog Sample3"/>
        <TextBlock Text="{Binding Time, StringFormat=時刻:{0}}"/>

        <StackPanel Orientation="Horizontal" HorizontalAlignment="Center">
            <Button Content="OK" Style="{StaticResource MaterialDesignFlatButton}"
                    Command="{x:Static materialDesign:DialogHost.CloseDialogCommand}">
                <Button.CommandParameter>
                    <system:Boolean>True</system:Boolean>
                </Button.CommandParameter>
            </Button>
            <Button Content="Cancel" Style="{StaticResource MaterialDesignFlatButton}"
                Command="{x:Static materialDesign:DialogHost.CloseDialogCommand}">
                <Button.CommandParameter>
                    <system:Boolean>False</system:Boolean>
                </Button.CommandParameter>
            </Button>
        </StackPanel>
    </StackPanel>
</UserControl>
using Livet;
using System;

namespace DialogDemo.ViewModels
{
    public class SampleDialogViewModel : ViewModel
    {
        public SampleDialogViewModel()
        {
            Time = DateTime.Now;
        }

        #region Time変更通知プロパティ
        private DateTime _Time;

        public DateTime Time
        {
            get
            { return _Time; }
            set
            { 
                if (_Time == value)
                    return;
                _Time = value;
                RaisePropertyChanged();
            }
        }
        #endregion

    }
}
 このダイアログはViewModelのTimeプロパティで指定された時刻を表示するだけのダイアログです。
 OKボタンとCancelボタンにはそれぞれ戻り値を設定しています。

<UserControl x:Class="DialogDemo.Views.Dialog3"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
             xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
             xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
             xmlns:l="http://schemas.livet-mvvm.net/2011/wpf"
             xmlns:vm="clr-namespace:DialogDemo.ViewModels"
             mc:Ignorable="d" 
             d:DesignHeight="300" d:DesignWidth="300">
    <UserControl.DataContext>
        <vm:Dialog3ViewModel/>
    </UserControl.DataContext>
    
    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition />
            <ColumnDefinition />
        </Grid.ColumnDefinitions>
               
        <materialDesign:DialogHost Grid.Column="0" Identifier="Dialog1" CloseOnClickAway="True">
            <StackPanel>
                <TextBlock Text="{Binding Result1, StringFormat=ダイアログ1の結果:{0}}"/>
                <Button Content="ダイアログを表示">
                    <i:Interaction.Triggers>
                        <i:EventTrigger EventName="Click">
                            <l:LivetCallMethodAction MethodTarget="{Binding}" MethodName="Open1"/>
                        </i:EventTrigger>
                    </i:Interaction.Triggers>
                </Button>
            </StackPanel>
        </materialDesign:DialogHost>

        <materialDesign:DialogHost Grid.Column="1" Identifier="Dialog2">
            <StackPanel>
                <TextBlock Text="{Binding Result2, StringFormat=ダイアログ2の結果:{0}}"/>
                <Button Content="ダイアログを表示">
                    <i:Interaction.Triggers>
                        <i:EventTrigger EventName="Click">
                            <l:LivetCallMethodAction MethodTarget="{Binding}" MethodName="Open2"/>
                        </i:EventTrigger>
                    </i:Interaction.Triggers>
                </Button>
            </StackPanel>
        </materialDesign:DialogHost>
    </Grid>
</UserControl>
using DialogDemo.Views;
using Livet;
using MaterialDesignThemes.Wpf;

namespace DialogDemo.ViewModels
{
    public class Dialog3ViewModel : ViewModel
    {

        #region Result1変更通知プロパティ
        private bool _Result1;

        public bool Result1
        {
            get
            { return _Result1; }
            set
            { 
                if (_Result1 == value)
                    return;
                _Result1 = value;
                RaisePropertyChanged();
            }
        }
        #endregion

        public async void Open1()
        {
            var dialog = new SampleDialog()
            {
                DataContext = new SampleDialogViewModel()
            };

            // ダイアログ外をクリックして閉じた場合はnullが返ってくる
            var result = await DialogHost.Show(dialog, "Dialog1");
            if(result != null) Result1 = (bool)result;
        }


        #region Result2変更通知プロパティ
        private bool _Result2;

        public bool Result2
        {
            get
            { return _Result2; }
            set
            { 
                if (_Result2 == value)
                    return;
                _Result2 = value;
                RaisePropertyChanged();
            }
        }
        #endregion

        public async void Open2()
        {
            var dialog = new SampleDialog()
            {
                DataContext = new SampleDialogViewModel()
            };

            var result = await DialogHost.Show(dialog, "Dialog2");

            Result2 = (bool)result;
        }

    }
}
 このサンプルのダイアログは以下の様に表示されます。
DialogSample3.png
 このサンプルコードではDialogHostを2つ用意しました。
 DialogHostを複数使用する場合はDialogHostのIdentifierプロパティに名前を付けておきます。
 この名前を使用してダイアログを表示させるDialogHostを指定します。
 名前を付けていないなどで使用するDialogHostが特定できない場合は例外が発生します。
 1つめのDialogHostではCloseOnClickAwayプロパティにTrueを指定しています。
 CloseOnClickAwayがTrueの場合はダイアログ外側の黒背景部分をクリックするとダイアログが閉じます。
 ボタンをクリックした際にViewModelのメソッドでダイアログの表示を行っています。
 Open1メソッド(Open2もほぼ同じ)では表示するダイアログインスタンスを作成します。(必要があればDataContentにViewModelを設定します。)
 DialogHostのShowメソッドに表示したいダイアログインスタンスと使用するDialogHostの名前を指定します。
 Showメソッドは戻り値にダイアログを閉じた際のCommandParameterの値を返します。
 欄外(黒背景)をクリックしてダイアログを閉じた場合は戻り値が存在しないためnullが返ってきます。

4.DialogHostのIsOpenプロパティを使用する方法
 DialoghostのIsOpenプロパティを使用するとコマンドを使用しなくてもダイアログの表示、非表示を制御できます。
 まず、このサンプルで表示するダイアログのコードです。
<UserControl x:Class="DialogDemo.Views.NameDialog"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
             xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
             xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
             xmlns:l="http://schemas.livet-mvvm.net/2011/wpf"
             mc:Ignorable="d" 
             d:DesignHeight="300" d:DesignWidth="300">
    <StackPanel Margin="10">
        <TextBlock Text="Dialog Sample4"/>
        <TextBox Text="{Binding Name}" materialDesign:HintAssist.Hint="(名前)"/>

        <StackPanel Orientation="Horizontal" HorizontalAlignment="Center">
            <Button Content="OK" Style="{StaticResource MaterialDesignFlatButton}">
                <i:Interaction.Triggers>
                    <i:EventTrigger EventName="Click">
                        <l:LivetCallMethodAction MethodTarget="{Binding}" MethodName="AcceptDialog"/>
                    </i:EventTrigger>
                </i:Interaction.Triggers>
            </Button>
            <Button Content="Cancel" Style="{StaticResource MaterialDesignFlatButton}">
                <i:Interaction.Triggers>
                    <i:EventTrigger EventName="Click">
                        <l:LivetCallMethodAction MethodTarget="{Binding}" MethodName="CancelDialog"/>
                    </i:EventTrigger>
                </i:Interaction.Triggers>
            </Button>
        </StackPanel>
    </StackPanel>
</UserControl>
 このダイアログは名前入力欄を持つダイアログです。
 OKボタンを押した際にはAcceptDialogメソッドを、Cancelボタンを押した際にはCancelDialogメソッドが呼ばれるようになっています。
 ただ閉じるだけなら共通のメソッドがあればよいのですが、OKボタンとCancelボタンどちらが押されたかを判断するために別々のメソッドを割り当てています。
<UserControl x:Class="DialogDemo.Views.Dialog4"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
             xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
             xmlns:l="http://schemas.livet-mvvm.net/2011/wpf"
             xmlns:vm="clr-namespace:DialogDemo.ViewModels"
             xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
             mc:Ignorable="d" 
             d:DesignHeight="300" d:DesignWidth="300">
    <UserControl.DataContext>
        <vm:Dialog4ViewModel/>
    </UserControl.DataContext>

    <materialDesign:DialogHost DialogContent="{Binding DialogView}"
                               IsOpen="{Binding IsDialogOpen}">
        <StackPanel>
            <TextBlock Text="Dialog Sample4"/>
            <TextBlock Text="DialogHostのIsOpenによるダイアログ制御"/>
            <TextBlock Text="{Binding Name, StringFormat=名前:{0}}"/>
            <Button Content="ダイアログを表示">
                <i:Interaction.Triggers>
                    <i:EventTrigger EventName="Click">
                        <l:LivetCallMethodAction MethodTarget="{Binding}" MethodName="OpenDialog"/>
                    </i:EventTrigger>
                </i:Interaction.Triggers>
            </Button>
        </StackPanel>
    </materialDesign:DialogHost>
</UserControl>
using DialogDemo.Views;
using Livet;

namespace DialogDemo.ViewModels
{
    public class Dialog4ViewModel : ViewModel
    {
        public Dialog4ViewModel()
        {
            IsDialogOpen = false;
        }

        #region Name変更通知プロパティ
        private string _Name;

        public string Name
        {
            get
            { return _Name; }
            set
            { 
                if (_Name == value)
                    return;
                _Name = value;
                RaisePropertyChanged();
            }
        }
        #endregion

        #region IsDialogOpen変更通知プロパティ
        private bool _IsDialogOpen;

        public bool IsDialogOpen
        {
            get
            { return _IsDialogOpen; }
            set
            { 
                if (_IsDialogOpen == value)
                    return;
                _IsDialogOpen = value;
                RaisePropertyChanged();
            }
        }
        #endregion


        #region DialogView変更通知プロパティ
        private object _DialogView;

        public object DialogView
        {
            get
            { return _DialogView; }
            set
            { 
                if (_DialogView == value)
                    return;
                _DialogView = value;
                RaisePropertyChanged();
            }
        }
        #endregion

        public void OpenDialog()
        {
            Name = "";
            DialogView = new NameDialog()
            {
                DataContext = this
            };

            IsDialogOpen = true;
        }

        public void AcceptDialog()
        {
            IsDialogOpen = false;
        }

        public void CancelDialog()
        {
            IsDialogOpen = false;
            Name = "";
        }
    }
}
 このコードを実行すると以下の様なダイアログが表示されます。
DialogSample4.png
 ダイアログの表示・非表示をViewModelのIsDialogOpen(DialogHostのIsOpenとバインディング)で制御します。
 ダイアログを表示するのはDialog4、ダイアログを閉じるのはNameDialogの役目です。
 異なるViewでIsDialogOpenプロパティにアクセスする必要があるため、このサンプルではDialog4とNameDialog共通のViewModelを作成しました。(他の方法でもかまいません。とにかく、両方のViewからIsDialogOpenを設定できればOK)
 OpenDialogメソッドでは表示するダイアログインスタンスを作成し(DialogHostのDialogContentにバインディングしてある)、IsDialogOpenをtrueにしています。
 ダイアログを閉じる際にはIsDialogOpenをfalseにするだけです。


 ダイアログを表示する方法を4種類紹介しましたが、個人的には2番目か3番目の方法が使いやすいと思っています。
 
スポンサーサイト

【Material Design Toolkit】 Snackbar

 Snackbarは短いメッセージの通知を行えるコントロールです。
 Material Design ToolkitのSnackbarではメッセージを表示するだけでなく、ボタンを1つ設置しボタンを押した際に処理を実行させることもできます。
<Grid>
    <Grid.RowDefinitions>
        <RowDefinition Height="*"/>
        <RowDefinition Height="*"/>
    </Grid.RowDefinitions>
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="*"/>
        <ColumnDefinition Width="*"/>
        <ColumnDefinition Width="*"/>
    </Grid.ColumnDefinitions>

    <GroupBox Grid.Row="0" Grid.Column="0" Header="メッセージのみ">
        <Grid>
            <StackPanel VerticalAlignment="Center">
                <TextBlock Text="Snackbarにメッセージのみを表示する場合"/>
                <ToggleButton IsChecked="{Binding ElementName=Snack1, Path=IsActive, Mode=TwoWay}"
                                Margin="10"/>
            </StackPanel>

            <materialDesign:Snackbar Name="Snack1" Message="Snackbar Message" IsActive="False"/>
        </Grid>
    </GroupBox>
                
    <GroupBox Grid.Row="0" Grid.Column="1" Header="Action Button付き">
        <Grid>
            <StackPanel VerticalAlignment="Center">
                <TextBlock Text="Actionボタン付きSnackbar"/>
                <TextBlock Text="Actionボタンが押されるとActionClickイベントが発生する"/>
                <ToggleButton IsChecked="{Binding ElementName=Snack2, Path=IsActive, Mode=TwoWay}"
                                Margin="10"/>
            </StackPanel>

            <materialDesign:Snackbar Name="Snack2" IsActive="True" HorizontalAlignment="Stretch">
                <materialDesign:SnackbarMessage Content="{Binding Count}" ActionContent="カウントアップ">
                    <i:Interaction.Triggers>
                        <i:EventTrigger EventName="ActionClick">
                            <l:LivetCallMethodAction MethodTarget="{Binding}" MethodName="CountUp"/>
                        </i:EventTrigger>
                    </i:Interaction.Triggers>
                </materialDesign:SnackbarMessage>
            </materialDesign:Snackbar>
        </Grid>
    </GroupBox>

    <GroupBox Grid.Row="1" Grid.Column="0" Header="MessageQueueを使う場合その1">
        <Grid>
            <StackPanel VerticalAlignment="Center">
                <TextBlock Text="MessageQueueを使ってメッセージを表示する"/>
                <TextBlock Text="「送る」ボタンを押すとメッセージキューにメッセージを送信する"/>
                <Button Content="送る" Width="80">
                    <i:Interaction.Triggers>
                        <i:EventTrigger EventName="Click">
                            <l:LivetCallMethodAction MethodTarget="{Binding}" MethodName="SendMessage"/>
                        </i:EventTrigger>
                    </i:Interaction.Triggers>
                </Button>
            </StackPanel>

            <materialDesign:Snackbar MessageQueue="{Binding MessageQueue1}"/>
        </Grid>
    </GroupBox>

    <GroupBox Grid.Row="1" Grid.Column="1" Header="MessageQueueを使う場合その2">
        <Grid>
            <StackPanel VerticalAlignment="Center">
                <TextBlock Text="MessageQueueを使ってAction付きメッセージを表示する"/>
                <TextBlock Text="「送る」ボタンを押すとメッセージキューにメッセージを送信する"/>
                <TextBlock Text="「カウントアップ」ボタンを押すと数値が上昇する"/>
                <TextBlock Text="{Binding Total, StringFormat=ボタンを押した回数 {0}}"/>
                <Button Content="送る" Width="80">
                    <i:Interaction.Triggers>
                        <i:EventTrigger EventName="Click">
                            <l:LivetCallMethodAction MethodTarget="{Binding}" MethodName="SendActionMessage"/>
                        </i:EventTrigger>
                    </i:Interaction.Triggers>
                </Button>
            </StackPanel>

            <materialDesign:Snackbar MessageQueue="{Binding MessageQueue2}"/>
        </Grid>
    </GroupBox>

    <GroupBox Grid.Row="0" Grid.RowSpan="2" Grid.Column="2" Header="カラーバリエーション">
        <StackPanel>
            <StackPanel.Resources>
                <ResourceDictionary>
                    <ResourceDictionary.MergedDictionaries>
                        <!-- ActionButtonStyleを使う為に必要 -->
                        <ResourceDictionary Source="pack://application:,,,/MaterialDesignThemes.Wpf;component/Themes/MaterialDesignTheme.Snackbar.xaml" />
                    </ResourceDictionary.MergedDictionaries>
                </ResourceDictionary>
            </StackPanel.Resources>
            <materialDesign:Snackbar IsActive="True" Margin="10">
                <materialDesign:SnackbarMessage Content="デフォルト(Accent)" ActionContent="Action"/>
            </materialDesign:Snackbar>

            <materialDesign:Snackbar IsActive="True" Margin="10"
                                        ActionButtonStyle="{StaticResource MaterialDesignSnackbarActionLightButton}">
                <materialDesign:SnackbarMessage Content="Primary Light" ActionContent="Action"/>
            </materialDesign:Snackbar>

            <materialDesign:Snackbar IsActive="True" Margin="10"
                                        ActionButtonStyle="{StaticResource MaterialDesignSnackbarActionMidButton}">
                <materialDesign:SnackbarMessage Content="Primary Mid" ActionContent="Action"/>
            </materialDesign:Snackbar>

            <materialDesign:Snackbar IsActive="True" Margin="10"
                                        ActionButtonStyle="{StaticResource MaterialDesignSnackbarActionDarkButton}">
                <materialDesign:SnackbarMessage Content="Primary Dark" ActionContent="Action"/>
            </materialDesign:Snackbar>

        </StackPanel>
    </GroupBox>
</Grid>
using Livet;
using MaterialDesignThemes.Wpf;
using System;
using System.Linq;

namespace MdDemo.ViewModels
{
    public class MainWindowViewModel : ViewModel
    {
        public MainWindowViewModel()
        {
            Count = 0;

            MessageQueue1 = new SnackbarMessageQueue();
            MessageQueue2 = new SnackbarMessageQueue();
        }

        #region Count変更通知プロパティ
        private int _Count;

        public int Count
        {
            get
            { return _Count; }
            set
            { 
                if (_Count == value)
                    return;
                _Count = value;
                RaisePropertyChanged();
            }
        }
        #endregion

        public void CountUp()
        {
            Count++;
        }

        public SnackbarMessageQueue MessageQueue1 { get; }

        public void SendMessage()
        {
            MessageQueue1.Enqueue("メッセージ:" + DateTime.Now);
        }

        public SnackbarMessageQueue MessageQueue2 { get; }



        #region Total変更通知プロパティ
        private int _Total;

        public int Total
        {
            get
            { return _Total; }
            set
            { 
                if (_Total == value)
                    return;
                _Total = value;
                RaisePropertyChanged();
            }
        }
        #endregion


        public void SendActionMessage()
        {
            Total = 0;
            foreach(var n in Enumerable.Range(1, 5))
            {
                MessageQueue2.Enqueue(
                    "メッセージ:" + n,
                    "カウントアップ",
                    () => Total++);
            }
        }
    }
}
 Snackbarは以下の様に表示されます。
MaterialDesign Snackbar
 Snackbarに固定メッセージを表示させるだけの場合はSnackbarコントロールのMessageプロパティに表示させたいメッセージを入力しIsActiveプロパティでSnackbarの表示、非表示を制御します。
 この方法の場合IsActiveプロパティがTrueの間はずっとSnackbarが表示されます。

 Snackbarにアクションボタンを表示させる場合はSnackbarMessageを使用します。
 SnackbarMessageのContentに表示するメッセージを、ActionContentにアクションボタンのコンテンツを指定します。
 アクションボタンがクリックされた際にはActionClickイベントが発生します。
 サンプルコードではアクションボタン(カウントアップ)を押した際にCountをインクリメントしています。

 SnackbarへのメッセージはMessageQueueを使って送信することもできます。(たぶんこっちが本来の使い方)
 「MessageQueueを使う場合その1」では「送る」ボタンを押す際にボタンを押した際の時刻入りメッセージをMessageQueueに送信します。
 SnackbarはMessageQueueに送信があった場合、送られたメッセージを一定時間表示した後にSnackbarを非表示にします。 (Snackbarの表示・非表示が自動で行われます)
 ViewModelでSnackbarMessageQueue型のプロパティを用意し、SnackbarのMessageQueueプロパティとデータバインディングします。
 SnackbarMessageQueueのEnqueueメソッドでメッセージの送信を行います。
 メッセージのみ送る場合はEnqueueメソッドの引数に表示するテキストを指定するだけです。

 MessageQueueでアクション付きメッセージを送りたい場合はEnqueueメソッドの引数にメッセージの他にアクションボタンのコンテンツとアクションを指定します。
 このサンプルでは「カウントアップ」ボタンを押した際にTotalプロパティをインクリメントするアクションを指定しています。
 サンプルコードの様に連続してメッセージを送信した場合、送信した順番にSnackbarが表示されます。
 次のメッセージが送信されたからといって表示中のメッセージが即座に変更されることはありません。(一定時間が過ぎた後に次が表示されます)

 最後にアクションボタンのカラーバリエーションを紹介します。
 アクションボタンのスタイルを指定することでアクションボタンの色を変えることができます。
 アクションボタンのスタイルを指定するためにはResourceDictionaryにSnackbar.xamlを追加する必要があります。

テーマ : プログラミング
ジャンル : コンピュータ

【Material Design Toolkit】 DatePicker

 DatePickerは日付を選択するためのコントロールで、TimePickerとほぼ同じ動きをします。
 Material Design Toolkitでは2種類のスタイルが定義されていますが、そのうちの1つはフロートヒント機能をONにしただけなので見た目や使い方はほぼ同じです。
<StackPanel>
    <DatePicker SelectedDate="{Binding Date}" Margin="10"/>
    <DatePicker SelectedDate="{Binding Date2}" Margin="10"
                Style="{StaticResource MaterialDesignFloatingHintDatePicker}"
                materialDesign:HintAssist.Hint="日付"
                SelectedDateFormat="Long"
                IsTodayHighlighted="False"
                FirstDayOfWeek="Monday"
                DisplayDateStart="2017/7/1" DisplayDateEnd="2017/7/25"/>
</StackPanel>
 このコードを実行すると以下の様になります。
MaterialDesign_DatePicker-1.png MaterialDesign_DatePicker-2.png
 TimePickerと同じような見た目で、日付テキストボックスとカレンダーボタンが表示されます。
 テキストボックスに日付を入力することもできますし、カレンダーから指定することもできます。
 SelectedDateFormatプロパティは日付テキストの書式設定でShort(デフォルト)の場合は「2017/07/01」の様に表示されます。
 Longの場合は「2017年7月2日」の様に表示されます。
 IsTodayHighlightedプロパティがTrueの場合はカレンダー表示時に今日の日付がハイライトされます。
 FirstDayOfWeekプロパティを変更するとカレンダーの週初めの曜日を変更できます。
 DisplayDateStartとDisplayDataEndはカレンダーに表示する範囲を指定できます。
 画像のカレンダーは7/1から7/25までを表示させるようにしているので、26日以降が非表示になっています。

テーマ : プログラミング
ジャンル : コンピュータ

【Material Design Toolkit】 TimePicker

 TimePickerは名前の通り時刻を指定するためのコントロールです。
 前回紹介したClockも時刻の指定は可能でしたが、TimePickerの方がより使いやすいコントロールになっています。(というかClockはTimePickerの一部と考えたほうがよさそうです。)
 このコードを実行すると以下の様になります。
MaterialDesign TimePicker1 MaterialDesign TimePicker2
 TimePickerは時刻の表示・編集用のテキストボックスと時計マークのボタンで構成されています。
 時計マークボタンを押すとClockが表示され時刻の変更ができます。
 テキストボックスから時刻を編集することも可能です。
 デフォルトではClockの表示はAM・PM表示ですが、Is24HoursをTrueにすることで24時間表記に変更できます。
 SelectedTimeFormatをLongにすることでTimePickerの時刻表示を秒まで表示することができますが、Clockコントロールでは秒の変更はできません。(テキスト入力でのみ変更可能です)
 FlowDirectionをRightToLeftにすると時計マークボタンとテキストボックスの順序が逆になります。

 TimePickerには標準スタイルの他にMaterialDesignFloatingHintTimePickerが定義されていますが、このスタイルはフロートヒントを表示させているだけで他の設定は標準スタイルと同じです。  

テーマ : プログラミング
ジャンル : コンピュータ

【Material Design Toolkit】 Clock

 ClockはWPFにはないコントロールで時間と分を指定することで時刻を変更することもできます。(秒の指定は無理みたいです)
<StackPanel Orientation="Horizontal">
    <GroupBox Header="AM.PM" Margin="5">
        <materialDesign:Clock Time="{Binding Date}" 
                                DisplayAutomation="Cycle"
                                DisplayMode="Hours"/>
    </GroupBox>

    <GroupBox Header="24時間表記" Margin="5">
        <materialDesign:Clock Time="{Binding Date2}" Is24Hours="True"/>
    </GroupBox>

    <GroupBox Header="分だけ指定" Margin="5">
        <materialDesign:Clock Time="{Binding Date3}"
                                DisplayAutomation="ToMinutesOnly"
                                DisplayMode="Minutes"/>
    </GroupBox>
</StackPanel>
 このコードを実行すると以下の様に表示されます。
MaterialDesign Clock
 TimeプロパティにDateTime型のプロパティをデータバインディングします。
 Is24HoursプロパティをfalseにするとAM・PMで時刻を表示します。(左のコントロール)
 Is24Hoursプロパティをtrueにすると24時間表記で時刻を表示します。(真ん中のコントロール)
 Clockコントロールでは見ての通り、時間と分を両方同時に表示しません。
 どちらを表示するかはDisplayModeプロパティで指定できます。
 DisplayAutomationプロパティをCycleに指定することで時間を指定すると分が表示されます。
 そして分を指定すると時間表示に戻ります。
 DisplayModeとDisplayAutomationを指定することで分だけ表示・変更するといったことも可能です。
 

テーマ : プログラミング
ジャンル : コンピュータ

カレンダー
07 | 2017/08 | 09
- - 1 2 3 4 5
6 7 8 9 10 11 12
13 14 15 16 17 18 19
20 21 22 23 24 25 26
27 28 29 30 31 - -
全記事表示リンク

全ての記事を表示する

カテゴリ
タグリスト

月別アーカイブ
08  07  06  05  04  03  02  01  12  11  10  09  08  07  06  04  03  02  01  12  11  10  09  08  07  06  05  04  03  02  01  12  11  10  09 
最新記事
リンク
最新コメント
検索フォーム
Amazon