DictionaryでCustom Buttonを作り、MainWindowで使用する方法

# やりたい事
#####1. 自分でボタンをデザインしたい。
#####2. 詳細デザインをDictionary.xamlに記述し、"CustomButton"をMainWindow.xamlで使用する。**MainWindow.xaml内部をすっきりさせたい。**

# 結果
下の画像が結果である。
一番上(Button1)は、Windowsのチュートリアル[1]に記述されていたもの。二番目(Button2)は、参考文献[2]に記述されていたもの。三番目(Button3)は、デフォルトを表わす。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/305726/e2d8bb28-6484-4e73-4af7-00faa9a73e94.png)
###参考文献
[1] [Microsoftのチュートリアル](https://docs.microsoft.com/ja-jp/dotnet/framework/wpf/controls/walkthrough-create-a-button-by-using-xaml)
 自分の知識レベルが低いのか? Microsoftのreferenceは分かりにくい。でもこのチュートリアルは分かりやすいです。
[2] [XAML UNLEASHED](https://www.pearson.com.au/9780672337222)
 xamlは、記述方法の慣れが必要で、参考資料が少ないですが、この書籍は分かりやすいと思います。初心者には、[こちら](https://www.amazon.co.jp/%E3%83%97%E3%83%AD%E3%81%AE%E3%81%9F%E3%82%81%E3%81%AEWindows%E3%82%B9%E3%83%88%E3%82%A2%E3%82%A2%E3%83%97%E3%83%AA%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%9F%E3%83%B3%E3%82%B0%E3%82%AC%E3%82%A4%E3%83%89-%E6%96%B0%E3%82%B7%E3%82%B9%E3%83%86%E3%83%A0%E3%81%B8%E3%81%AE%E5%AF%BE%E5%BF%9C%E3%81%A8%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%A0%E5%AE%9F%E8%A3%85%E3%81%AE%E3%83%9D%E3%82%A4%E3%83%B3%E3%83%88-%E6%A0%AA%E5%BC%8F%E4%BC%9A%E7%A4%BE%E3%82%B7%E3%82%B9%E3%83%86%E3%83%A0%E3%83%95%E3%83%AC%E3%83%B3%E3%83%89/dp/4797373229)を勧めます。しかも、中古本が安い。

# 詳細
自分でデザインしたボタンをDictionary.xamlに記述します。
ここで、デザインといっても、pngやjpgなどで作った画像データを埋め込むという意味ではありません。

```xml:Dictionary1.xaml
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                    xmlns:local="clr-namespace:WpfApp5">
    <GradientStopCollection x:Key="MyGlassGradientStopsResource">
        <GradientStop Color="WhiteSmoke" Offset="0.2" />
        <GradientStop Color="Transparent" Offset="0.4" />
        <GradientStop Color="WhiteSmoke" Offset="0.5" />
        <GradientStop Color="Transparent" Offset="0.75" />
        <GradientStop Color="WhiteSmoke" Offset="0.9" />
        <GradientStop Color="Transparent" Offset="1" />
    </GradientStopCollection>
    <LinearGradientBrush x:Key="MyGlassBrushResource" StartPoint="0,0" EndPoint="1,1" Opacity="0" GradientStops="{StaticResource MyGlassGradientStopsResource}" />
    <LinearGradientBrush x:Key="GrayBlueGradientBrush" StartPoint="0,0" EndPoint="1,1">
        <GradientStop Color="DarkGray" Offset="0" />
        <GradientStop Color="#CCCCFF" Offset="0.5" />
        <GradientStop Color="DarkGray" Offset="1" />
    </LinearGradientBrush>
<!-- Button1の始まり -->
    <Style TargetType="{x:Type Button}" x:Key="ButtonStyle">
        <Setter Property="Background" Value="{StaticResource GrayBlueGradientBrush}" />
        <Setter Property="Width" Value="80" />
        <Setter Property="Margin" Value="10" />
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type Button}">
                    <Grid Width="{TemplateBinding Width}"
                            Height="{TemplateBinding Height}" ClipToBounds="True">
                        <!-- Outer Rectangle with rounded corners. -->
                        <Rectangle x:Name="outerRectangle" HorizontalAlignment="Stretch"
                                    VerticalAlignment="Stretch" Stroke="{TemplateBinding Background}"
                                    RadiusX="20" RadiusY="20" StrokeThickness="5" Fill="Transparent" />

                        <!-- Inner Rectangle with rounded corners. -->
                        <Rectangle x:Name="innerRectangle" HorizontalAlignment="Stretch"
                                    VerticalAlignment="Stretch" Stroke="Transparent"
                                    StrokeThickness="20" Fill="{TemplateBinding Background}" RadiusX="20" RadiusY="20" />
                        <!-- Glass Rectangle -->
                        <Rectangle x:Name="glassCube" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" 
                                       StrokeThickness="2" RadiusX="10" RadiusY="10" Opacity="0" Fill="{StaticResource MyGlassBrushResource}"
                                       RenderTransformOrigin="0.5,0.5">
                            <Rectangle.Stroke>
                                <LinearGradientBrush StartPoint="0.5,0" EndPoint="0.5,1">
                                    <LinearGradientBrush.GradientStops>
                                        <GradientStop Offset="0.0" Color="LightBlue" />
                                        <GradientStop Offset="1.0" Color="Gray" />
                                    </LinearGradientBrush.GradientStops>
                                </LinearGradientBrush>
                            </Rectangle.Stroke>
                            <Rectangle.RenderTransform>
                                <TransformGroup>
                                    <ScaleTransform />
                                    <RotateTransform />
                                </TransformGroup>
                            </Rectangle.RenderTransform>
                            <Rectangle.BitmapEffect>
                                <BevelBitmapEffect />
                            </Rectangle.BitmapEffect>
                        </Rectangle>
                        <!-- Present Text of the button. -->
                        <DockPanel Name="myContentPresenterDockPanel">
                            <ContentPresenter x:Name="myContentPresenter" Margin="20" Content="{TemplateBinding  Content}" TextBlock.Foreground="Black" />
                        </DockPanel>
                    </Grid>
                    <ControlTemplate.Triggers>
                        <Trigger Property="IsMouseOver" Value="True">
                            <Setter Property ="Rectangle.Stroke" TargetName="outerRectangle" Value="{DynamicResource {x:Static SystemColors.HighlightBrushKey}}" />
                            <!-- Sets the glass opacity to 1, therefore, the           glass "appears" when user mouses over it. -->
                            <Setter Property="Rectangle.Opacity" Value="1" TargetName="glassCube" />
                            <!-- Makes the text slightly blurry as though you           were looking at it through blurry glass. -->
                            <Setter Property="ContentPresenter.BitmapEffect" TargetName="myContentPresenter">
                                <Setter.Value>
                                    <BlurBitmapEffect Radius="1" />
                                </Setter.Value>
                            </Setter>
                        </Trigger>
                        <Trigger Property="IsFocused" Value="true">
                            <Setter Property="Rectangle.Opacity" Value="1" TargetName="glassCube" />
                            <Setter Property="Rectangle.Stroke" TargetName="outerRectangle" Value="{DynamicResource {x:Static SystemColors.HighlightBrushKey}}" />
                            <Setter Property="Rectangle.Opacity" Value="1" TargetName="glassCube" />
                        </Trigger>
                        <!-- Animations that start when mouse enters and leaves button. -->
                        <EventTrigger RoutedEvent="Mouse.MouseEnter">
                            <EventTrigger.Actions>
                                <BeginStoryboard Name="mouseEnterBeginStoryboard">
                                    <Storyboard>
                                        <!-- This animation makes the glass rectangle shrink in the X direction. -->
                                        <DoubleAnimation Storyboard.TargetName="glassCube" 
                                                             Storyboard.TargetProperty= "(Rectangle.RenderTransform).(TransformGroup.Children)[0].(ScaleTransform.ScaleX)" By="-0.1" Duration="0:0:0.5" />
                                        <!-- This animation makes the glass rectangle shrink in the Y direction. -->
                                        <DoubleAnimation Storyboard.TargetName="glassCube"
                                                            Storyboard.TargetProperty="(Rectangle.RenderTransform).(TransformGroup.Children)[0].(ScaleTransform.ScaleY)"
                                                            By="-0.1" Duration="0:0:0.5" />
                                    </Storyboard>
                                </BeginStoryboard>
                            </EventTrigger.Actions>
                        </EventTrigger>
                        <EventTrigger RoutedEvent="Mouse.MouseLeave">
                            <EventTrigger.Actions>
                                <!-- Stopping the storyboard sets all animated properties back to default. -->
                                <StopStoryboard BeginStoryboardName="mouseEnterBeginStoryboard" />
                            </EventTrigger.Actions>
                        </EventTrigger>
                        <!-- Animation fires when button is clicked, causing glass to spin.  -->
                        <EventTrigger RoutedEvent="Button.Click">
                            <EventTrigger.Actions>
                                <BeginStoryboard>
                                    <Storyboard>
                                        <DoubleAnimation Storyboard.TargetName="glassCube" 
                                                             Storyboard.TargetProperty= "(Rectangle.RenderTransform).(TransformGroup.Children)[1].(RotateTransform.Angle)"
                                                             By="360" Duration="0:0:0.5" />
                                    </Storyboard>
                                </BeginStoryboard>
                            </EventTrigger.Actions>
                        </EventTrigger>
                    </ControlTemplate.Triggers>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
<!-- Button1の終わり -->

<!-- Button2の始まり -->
    <Style TargetType="Button" x:Key="CustomButton" >
        <Setter Property="Margin" Value="10" />
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="Button">
                    <Grid Width="{TemplateBinding Width}"
                            Height="{TemplateBinding Height}" ClipToBounds="True">
                        <Ellipse Width="100" Height="100">
                        <Ellipse.Fill>
                            <LinearGradientBrush StartPoint="0,0" EndPoint="0,1">
                                <GradientStop Offset="0" Color="Blue"/>
                                <GradientStop Offset="1" Color="Red"/>
                            </LinearGradientBrush>
                        </Ellipse.Fill>
                    </Ellipse>
                    <!-- Contentの中身をTemplateの中に埋め込むために以下が必要 -->
                        <DockPanel Name="myContentPresenterDockPanel1">
                            <ContentPresenter x:Name="myContentPresenter1" HorizontalAlignment="Center" VerticalAlignment="Center" Content="{TemplateBinding  Content}" TextBlock.Foreground="White" />
                        </DockPanel>
                    </Grid>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
<!-- Button2の終わり-->
</ResourceDictionary>
```

###重要なポイント
Dictonary1.xamlでButtonタイプを継承し、新しくButtonSyleを定義します。

```xml
<Style TargetType="{x:Type Button}" x:Key="ButtonStyle">
```

ボタンに機能を持たせるには、ControlTemplateの下に記述する必要があります。

```xml

<ControlTemplate>
             <ControlTemplate.Trigger>
                <EventTrigger>
                     -----------
                </EventTrigger>
             </ControlTemplate.Trigger>
</ControlTemplate>
```

上記のDictionary1.xamlで記述したButtonStyle(Button1用)のデザインを引継ぎ、MainWindow.xamlで利用する。利用するには、Style="{StaticResource ****}" を使う。

```xml
<Button Style="{StaticResource ButtonStyle}" Content="Button1"/>
```

```xml:MainWindow.xaml
<Window x:Class="WpfApp5.MainWindow"
        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:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:WpfApp5"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800" Background="Black">
    <Window.Resources>
        <ResourceDictionary>
            <ResourceDictionary.MergedDictionaries>
                <ResourceDictionary Source="/Dictionary1.xaml"/>
            </ResourceDictionary.MergedDictionaries>
        </ResourceDictionary>
    </Window.Resources>
    <StackPanel HorizontalAlignment="Left">
        <Button Style="{StaticResource ButtonStyle}" Content="Button1"/>
        <Button Style="{StaticResource CustomButton}" Content="Button2"/>
        <Button Content="Button3"/>
    </StackPanel>
</Window>
```

###最後に
今回の記事では、ボタンのカスタマイズだったので、xamlのみの変更修正です。
コードビハインドであるMainWindow.xaml.csには、デフォルトの内容です。