ホバー時のボタン背景色を変更する俺的ベストプラクティス

WPFで、ボタンのホバー時の背景色を変更するのに良い感じの方法を見つけたので、忘れないように書いておきます。

# はじめに

## ボタンに画像を表示

|![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/305299/8db573ab-0796-44ba-b6be-0bdfbca83834.png)
|:-:|

<details><summary>コード</summary><div>

```MainWindow.xaml

<Window x:Class="sample_button.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:sample_button"
        mc:Ignorable="d"
        Title="MainWindow" Height="300" Width="500">

    <Grid>
        <Button x:Name="btn" HorizontalAlignment="Center" VerticalAlignment="Center" Width="75" Height="75">
            <Image x:Name="btn_img" Source="images/sun.png" Margin="5"></Image>
        </Button>

    </Grid>
</Window>

```

</div></details>

やっぱりこういうのが簡単にできるのはいいですよね、でもボタンのデフォルトの背景色が残っちゃってるので、まだちょっと残念な感じです。背景色を変えてみましょう。

## ボタンの背景色を変更

|![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/305299/db2f2adb-0ac1-20f4-0e39-ef171163c584.png)
|:-:|

<details><summary>コード</summary><div>

```MainWindow.xaml

<Window x:Class="sample_button.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:sample_button"
        mc:Ignorable="d"
        Title="MainWindow" Height="300" Width="500">

    <Grid>
        <Button x:Name="btn" HorizontalAlignment="Center" VerticalAlignment="Center" Width="75" Height="75" Background="#FF94CEFF" BorderBrush="Blue" BorderThickness="3">
            <Image x:Name="btn_img" Source="images/sun.png" Margin="5"></Image>
        </Button>

    </Grid>
</Window>

```

</div></details>

できました。

## ホバー時は夕方にする
ここからが本題ですが、ホバー時には夕方っぽく、背景をオレンジ色にしてみたいと思います。

### 追加したコード

```xml:MainWindow.xaml-追加分

<Window.Resources>
    
    <Style TargetType="{x:Type Button}">
        <Style.Triggers>
            <Trigger Property="IsMouseOver" Value="true">
                <Setter Property="Background" Value="#FFFFE488"></Setter>
                <Setter Property="BorderBrush" Value="Red"></Setter>
            </Trigger>
        </Style.Triggers>
    </Style>

</Window.Resources>

```

<details><summary>すべてのコード</summary><div>

```MainWindow.xaml

<Window x:Class="sample_button.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:sample_button"
        mc:Ignorable="d"
        Title="MainWindow" Height="300" Width="500">

    <Window.Resources>
        
        <Style TargetType="{x:Type Button}">
            <Style.Triggers>
                <Trigger Property="IsMouseOver" Value="true">
                    <Setter Property="Background" Value="#FFFFE488"></Setter>
                    <Setter Property="BorderBrush" Value="Red"></Setter>
                </Trigger>
            </Style.Triggers>
        </Style>

    </Window.Resources>

    <Grid>
        <Button x:Name="btn" HorizontalAlignment="Center" VerticalAlignment="Center" Width="75" Height="75" Background="#FF94CEFF" BorderBrush="Blue" BorderThickness="3">
            <Image x:Name="btn_img" Source="images/sun.png" Margin="5"></Image>
        </Button>

    </Grid>
</Window>

```

</div></details>

|![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/305299/5252227d-6ae2-56f9-78ec-8f4744a1a212.png)
|:-:|

デフォルトのまま、全く変わっていないことが分かります。

この場合、[ControlTemplate](https://docs.microsoft.com/ja-jp/dotnet/api/system.windows.controls.controltemplate?view=netcore-3.1)を用いて、ボタンのスタイルを書き換える必要があります。

## ControlTemplateを追加
まずは、ホバーは置いておいて、ボタンのスタイルを作り直します。

```MainWindow.xaml

<Window x:Class="sample_button.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:sample_button"
        mc:Ignorable="d"
        Title="MainWindow" Height="300" Width="500">

    <Window.Resources>

        <ControlTemplate x:Key="buttonControlTemplate" TargetType="Button">
            <Grid>
                <Rectangle Fill="#FF94CEFF"/>
                <Border BorderBrush="Blue" BorderThickness="3"></Border>
                <ContentPresenter HorizontalAlignment="Center"
                          VerticalAlignment="Center"/>
            </Grid>
        </ControlTemplate>

        <Style TargetType="{x:Type Button}">
            <Setter Property="Template" Value="{StaticResource buttonControlTemplate}"/>
        </Style>

    </Window.Resources>

    <Grid>
        <Button x:Name="btn" HorizontalAlignment="Center" VerticalAlignment="Center" Width="75" Height="75">
            <Image x:Name="btn_img" Source="images/sun.png" Margin="5"></Image>
        </Button>

    </Grid>
</Window>

```

|![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/305299/ff402f00-8da8-69f9-a650-309467945e1c.png)
|:-:|

Button要素に、ControlTemplateとして``buttonControlTemplate``をあてています。今はButtonが1つしかないので、タグに直書きしてもいいのですが、後々この方が見やすいので、こうします。

タグ内で背景色を定義するのではなく、ボタンのスタイルを作り直し、背景を``#FF94CEFF``で埋めます。
ちなみに、``ContentPresenter``を書いておかないと、画像が表示されません。

また、ImageのMarginが若干効いていないように見えますが、これはBorderで詰まったのが原因なので、ButtonのBorderの3pxを考慮して、``Margin=8``とすると、元通りになります。

|![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/305299/5bcb5ece-cc6a-9155-8e2e-52745c8d7699.png)
|:-:|

この状態では、マウスホバー時に背景色の変化は無くなります。

## ホバー時のControlTemplateを追加
ここからは、調べるといくつか方法が出てきましたが、ホバー用にもう一つControlTemplateを追加するのが、一番簡単だと思います。

```MainWindow.xaml

<Window x:Class="sample_button.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:sample_button"
        mc:Ignorable="d"
        Title="MainWindow" Height="300" Width="500">

    <Window.Resources>

        <ControlTemplate x:Key="buttonControlTemplate" TargetType="Button">
            <Grid>
                <Rectangle Fill="#FF94CEFF"/>
                <Border BorderBrush="Blue" BorderThickness="3"></Border>
                <ContentPresenter HorizontalAlignment="Center"
                          VerticalAlignment="Center"/>
            </Grid>
        </ControlTemplate>

        <ControlTemplate x:Key="buttonHoverControlTemplate" TargetType="Button">
            <Grid>
                <Rectangle Fill="#FFFFE488"/>
                <Border BorderBrush="Red" BorderThickness="3"></Border>
                <ContentPresenter HorizontalAlignment="Center"
                          VerticalAlignment="Center"/>
            </Grid>
        </ControlTemplate>

        <Style TargetType="{x:Type Button}">
            <Setter Property="Template" Value="{StaticResource buttonControlTemplate}"/>

            <Style.Triggers>
                <Trigger Property="IsMouseOver" Value="true">
                    <Setter Property="Template" Value="{StaticResource buttonHoverControlTemplate}"/>
                </Trigger>
            </Style.Triggers>
        </Style>

    </Window.Resources>

    <Grid>
        <Button x:Name="btn" HorizontalAlignment="Center" VerticalAlignment="Center" Width="75" Height="75">
            <Image x:Name="btn_img" Source="images/sun.png" Margin="8"></Image>
        </Button>

    </Grid>
</Window>

```

ホバー時に適用するControlTemplateとして、新しく``buttonHoverControlTemplate``を用意し、Style.Triggersを使用して、ホバー時にControlTemplateを付け替えます。

|![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/305299/532a6740-5413-d8b4-5d16-b7d873e8eb42.png)
|:-:|

ホバー時に、しっかりと背景色が変わるようになりました！

#### 参考
- [ControlTemplate クラス | Microsoft Docs](https://docs.microsoft.com/ja-jp/dotnet/api/system.windows.controls.controltemplate?view=netcore-3.1)
- [テンプレート（WPF） - クラスライブラリ | ++C++; // 未確認飛行 C](https://ufcpp.net/study/dotnet/wpf_template.html)
- [ItemsControl 攻略 ～ 外観のカスタマイズ | grabacr.nét](http://grabacr.net/archives/1240)