【XAML】ボタンとそのトリガーに関する3つのサンプル

# この記事は

XAMLのボタン/ラベルに関する覚え書き

1. ボタンの上にマウスを置くと、ボタンの色が変わる
1. 照光式押しボタン （と、それに連動する何か）
1. 警告点滅表示

## 1. ボタンの上にマウスを置くと、ボタンの色が変わる

マイクロソフトの公式ドキュメントを参照する

ボタンの上にマウスを置く（MouseOver）と、ボタンの色が変わる

[依存関係プロパティ値の優先順位 - Microsoft Docs](https://docs.microsoft.com/ja-jp/dotnet/desktop/wpf/advanced/dependency-property-value-precedence)よりキャプチャ抜粋
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/272511/a6aa5c6a-b36b-0cb7-2ded-de46e98ab527.png)

> Button インスタンスからローカル値の Red を削除すると、スタイルが優先されるようになり、ボタンの Background の値はスタイルから取得されます。 スタイル内ではトリガーが優先されるので、ボタンはマウスでポイントすると青になり、それ以外の場合は緑になります。

先頭の`Button`タグから`Background="Red"`を削除すれば所望の動きになりそうだが、**実際はそうではない**。
このままだと、マウスオーバーしてもデフォルトの色が優先されて、青色にはならない。
`Template`プロパティの変更をあらたに追加する必要がある。

[Change color of Button when Mouse is over - Stack Overflow](https://stackoverflow.com/questions/20073294/change-color-of-button-when-mouse-is-over)

```diff_xml
-<Button Background="Red">
+<Button>
     <Button.Style>
         <Style TargetType="{x:Type Button}">
             <Setter Property="Background" Value="Green" />
+            <Setter Property="Template">
+                <Setter.Value>
+                    <ControlTemplate TargetType="{x:Type Button}">
+                        <Border Background="{TemplateBinding Background}">
+                            <ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center" />
+                        </Border>
+                    </ControlTemplate>
+                </Setter.Value>
+            </Setter>
             <Style.Triggers>
                 <Trigger Property="IsMouseOver" Value="True">
                     <Setter Property="Background" Value="Blue" />
                 </Trigger>
             </Style.Triggers>
         </Style>
     </Button.Style>
     Click
 </Button>
```

個人的には`Border`で囲むよりは、`Grid`で囲むほうが好み。

```xml
<Setter Property="Template">
    <Setter.Value>
        <ControlTemplate TargetType="{x:Type Button}">
            <Grid>
                <Border Background="{TemplateBinding Background}"/>
                <ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center" />
            </Grid>
        </ControlTemplate>
    </Setter.Value>
</Setter>
```

### 参考にしたサイト

マイクロソフト

- [ControlTemplate クラス](https://docs.microsoft.com/ja-jp/dotnet/api/system.windows.controls.controltemplate?view=net-5.0)
- [コントロールのスタイルを作成する方法 (WPF .NET)](https://docs.microsoft.com/ja-jp/dotnet/desktop/wpf/controls/how-to-create-apply-style)
- [コントロールのためのテンプレートを作成する方法 (WPF.NET)](https://docs.microsoft.com/ja-jp/dotnet/desktop/wpf/controls/how-to-create-apply-template)

ほか

- [未確認飛行 C テンプレート（WPF）](https://ufcpp.net/study/dotnet/wpf_template.html)
- [第4回　WPFの「リソース、スタイル、テンプレート」を習得しよう](https://www.atmarkit.co.jp/ait/articles/1009/07/news096_3.html)

## 2. 照光式押し釦

押すと光るボタンをつくる

[Google検索 - 照光式押し釦](https://www.google.com/search?q=%E7%85%A7%E5%85%89%E5%BC%8F%E6%8A%BC%E3%81%97%E9%87%A6)

### イメージ

緑ベースのボタンを押すと、色が明るくなるイメージ

![ダウンロード (1).gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/272511/c5a9672b-67a2-518c-1fb7-f7ef08d11484.gif)

### Style

```xml
                <Style x:Key="ToggleStyle" TargetType="{x:Type ToggleButton}">
                    <Setter Property="FontSize" Value="18" />
                    <Setter Property="BorderBrush" Value="Black" />
                    <Setter Property="BorderThickness" Value="5" />
                    <Setter Property="Cursor" Value="Hand" />
                    <Style.Triggers>
                        <Trigger Property="IsChecked" Value="True">
                            <Setter Property="Background" Value="LightGreen" />
                            <Setter Property="Foreground" Value="DarkBlue" />
                            <Setter Property="BorderBrush">
                                <Setter.Value>
                                    <LinearGradientBrush StartPoint="0,0" EndPoint="0.5, 1">
                                        <GradientStop Offset="0" Color="Black" />
                                        <GradientStop Offset="1" Color="Gray" />
                                    </LinearGradientBrush>
                                </Setter.Value>
                            </Setter>
                        </Trigger>
                        <Trigger Property="IsChecked" Value="False">
                            <Setter Property="Background" Value="DarkGreen" />
                            <Setter Property="Foreground" Value="Black" />
                        </Trigger>
                    </Style.Triggers>
                </Style>

```

### ControlTemplete

```xml
                <ControlTemplate x:Key="ToggleTemplate" TargetType="{x:Type ToggleButton}">
                    <Grid>
                        <Border
                        Background="{TemplateBinding Background}"
                        BorderBrush="{TemplateBinding BorderBrush}"
                        BorderThickness="{TemplateBinding BorderThickness}"
                        CornerRadius="2">
                            <Border.Effect>
                                <DropShadowEffect
                                x:Name="shadowEffect"
                                BlurRadius="6"
                                Direction="-90"
                                RenderingBias="Quality"
                                ShadowDepth="0" />
                            </Border.Effect>
                        </Border>
                        <ContentPresenter
                        x:Name="content"
                        HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
                        VerticalAlignment="{TemplateBinding VerticalContentAlignment}" />
                    </Grid>
                    <ControlTemplate.Triggers>
                        <Trigger Property="IsPressed" Value="True">
                            <Setter TargetName="content" Property="RenderTransform">
                                <Setter.Value>
                                    <TranslateTransform X="1.5" Y="2.5" />
                                </Setter.Value>
                            </Setter>
                        </Trigger>
                    </ControlTemplate.Triggers>
                </ControlTemplate>

```

### ボタンと、連動する何か

このボタンが押されたときに、他のなにかのスタイルを変える

```xml
        <!-- きっかけのボタン -->
        <ToggleButton
            x:Name="StartButton"
            ...
            Style="{StaticResource ToggleStyle}"
            Template="{StaticResource ToggleTemplate}" />

        <!-- ボタンと連動する何か -->
                        <Style.Triggers>
                            <DataTrigger Binding="{Binding ElementName=StartButton, Path=IsChecked}" Value="True">
                                <Setter Property="Width" Value="100" />
                                <Setter Property="Fill" Value="Aqua" />
                            </DataTrigger>
                        </Style.Triggers>

```

### 参考にしたサイト

マイクロソフト

- [チュートリアル: XAML を使用したボタンの作成](https://docs.microsoft.com/ja-jp/dotnet/desktop/wpf/controls/walkthrough-create-a-button-by-using-xaml)


スタックオーバーフロー

- [Conditional styling of an element in XAML](https://stackoverflow.com/questions/20207329/conditional-styling-of-an-element-in-xaml/20226859)
- [Change the background color of a toggle button when the toggle button is checked](https://stackoverflow.com/questions/5618800/change-the-background-color-of-a-toggle-button-when-the-toggle-button-is-checked/5619892)

ほか

- [ToggleButtonを実装してみたものの、ControlTemplateが上手く動かなかったので、最終的に成功したパターンをメモ](https://haronoid.hatenablog.com/entry/2019/02/09/225959)
- [Circular WPF Button Template](https://markheath.net/post/circular-wpf-button-template)


## 3. 警告点滅表示

プロパティが`true`の時だけ点滅するラベルをつくる

### イメージ

`Click!!`を押すと`Caution!!`ラベルが赤く点滅する

![ダウンロード.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/272511/4ce8e5be-fa9f-7368-b164-a060a8e0bef9.gif)

### View

`xxx.Resources`にまとめずに一筆書きしたら、ネストがとても深くなった

```xml:MainWindow.xaml
<Window
    x:Class="Project2107.Views.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:prism="http://prismlibrary.com/"
    Width="200"
    Height="200"
    prism:ViewModelLocator.AutoWireViewModel="True">
    <StackPanel>
        <Label
            Margin="10"
            Background="Red"
            Content="Caution !!"
            FontSize="12"
            Foreground="white">
            <Label.Style>
                <Style TargetType="{x:Type Label}">
                    <Style.Triggers>
                        <DataTrigger Binding="{Binding Flag.Value}" Value="true">
                            <DataTrigger.EnterActions>
                                <BeginStoryboard>
                                    <Storyboard>
                                        <!--  trueの時のアニメーション  -->
                                        <Storyboard>
                                            <DoubleAnimationUsingKeyFrames
                                                AutoReverse="True"
                                                RepeatBehavior="Forever"
                                                Storyboard.TargetProperty="Opacity">
                                                <LinearDoubleKeyFrame KeyTime="0:0:1.2" Value="1" />
                                                <LinearDoubleKeyFrame KeyTime="0:0:0.6" Value="0" />
                                            </DoubleAnimationUsingKeyFrames>
                                        </Storyboard>
                                    </Storyboard>
                                </BeginStoryboard>
                            </DataTrigger.EnterActions>
                            <DataTrigger.ExitActions>
                                <BeginStoryboard>
                                    <Storyboard>
                                        <!--  falseの時のアニメーション  -->
                                        <Storyboard>
                                            <DoubleAnimationUsingKeyFrames
                                                AutoReverse="True"
                                                RepeatBehavior="Forever"
                                                Storyboard.TargetProperty="Opacity">
                                                <LinearDoubleKeyFrame KeyTime="0:0:1" Value="1" />
                                                <LinearDoubleKeyFrame KeyTime="0:0:1" Value="0" />
                                            </DoubleAnimationUsingKeyFrames>
                                        </Storyboard>
                                    </Storyboard>
                                </BeginStoryboard>
                            </DataTrigger.ExitActions>
                        </DataTrigger>
                    </Style.Triggers>
                </Style>
            </Label.Style>
        </Label>
        <Button Command="{Binding Command}" Content="Click!!" />
    </StackPanel>
</Window>
```
### ViewModel

ボタンをクリックすると、フラグのON/OFFが入れ替わる

フラグのON/OFFに応じて、Viewの点滅がスタート/ストップする

```cs:MainWindowViewModel.cs
using Prism.Mvvm;
using Reactive.Bindings;
using System.Diagnostics;

namespace Project2107.ViewModels
{
    public class MainWindowViewModel : BindableBase
    {
        public ReactiveProperty<bool> Flag { get; private set; } = new ReactiveProperty<bool>(true);
        public ReactiveCommand Command { get; } = new ReactiveCommand();
        public MainWindowViewModel()
        {
            Command.Subscribe(() => {
                Flag.Value = !Flag.Value;
                Debug.WriteLine($"{Flag.Value}");
            });
        }
    }
}
```

### 参考にしたサイト

- [【WPF】LabelやTextBlockの文字列を点滅させる方法](https://mitosuya.net/wpf-flash-string)
- [WPFでプロパティの変更をトリガーにしてアニメーションするときにハマったこと](https://silatori.hatenablog.com/entry/2018/06/27/%E3%83%97%E3%83%AD%E3%83%91%E3%83%86%E3%82%A3%E3%81%AE%E5%A4%89%E6%9B%B4%E3%82%92%E3%83%88%E3%83%AA%E3%82%AC%E3%83%BC%E3%81%AB%E3%81%97%E3%81%A6%E3%82%A2%E3%83%8B%E3%83%A1%E3%83%BC%E3%82%B7%E3%83%A7)