WPF でハイコントラスト対応したい

ベストな方法かはわかりませんが、以下のような感じで出来ました。

1. `SystemParameters.HighContrastKey` を添付プロパティにバインド
2. その値をトリガーにしてスタイルの設定を分ける


## やってみよう

`SystemParameters.HighContrastKey` を `DynamicResource` マークアップ拡張でとってくるとハイコントラストの設定が変わったときに動的に値が変わるようになります。
それを適当な自作添付プロパティにバインドすることでハイコントラストの設定が変わったときに値が変わる印として使えます。あとは、その添付プロパティの値をトリガーにして設定する色を `Style` で設定するようにすればいけました。


ハイコントラストかどうかの値を保持するだけの添付プロパティ。

```csharp:HighContrast.cs
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;

namespace WpfHighContrast
{
    public class HighContrast
    {
        public static bool GetValue(DependencyObject obj)
        {
            return (bool)obj.GetValue(ValueProperty);
        }

        public static void SetValue(DependencyObject obj, bool value)
        {
            obj.SetValue(ValueProperty, value);
        }

        public static readonly DependencyProperty ValueProperty =
            DependencyProperty.RegisterAttached("Value", typeof(bool), typeof(HighContrast), new PropertyMetadata(false));
    }
}
```

そして、これを使って `Style` で色を出しわけます。例として TextBox の背景色と前景色を変えてみました。

```xml:MainWindow.xaml
<Window x:Class="WpfHighContrast.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:WpfHighContrast"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800">
    <StackPanel>
        <TextBox>
            <TextBox.Style>
                <Style TargetType="TextBox">
                    <!-- ハイコントラストの設定が変わると、この添付プロパティの値が変わる -->
                    <Setter Property="local:HighContrast.Value" Value="{DynamicResource {x:Static SystemParameters.HighContrastKey}}" />
                    <Style.Triggers>
                        <!-- データトリガーで色の設定を分ける -->
                        <DataTrigger Binding="{Binding RelativeSource={RelativeSource Self}, Path=(local:HighContrast.Value)}" Value="False">
                            <Setter Property="Foreground" Value="White" />
                            <Setter Property="Background" Value="ForestGreen" />
                        </DataTrigger>
                        <DataTrigger Binding="{Binding RelativeSource={RelativeSource Self}, Path=(local:HighContrast.Value)}" Value="True">
                            <!-- もし独自色を出したければここに設定 -->
                        </DataTrigger>
                    </Style.Triggers>
                </Style>
            </TextBox.Style>
        </TextBox>
    </StackPanel>
</Window>
```

### 実行結果

ハイコントラストの設定をしてない状態で起動します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/70288/3defb12d-2351-7e7b-5660-4003560494b8.png)

起動したまま Windows 10 の設定でハイコントラストをオンにしてみました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/70288/9a1807e3-52a0-c2a4-9b91-752c57c9d562.png)

実行時にちゃんと色が変わってますね。ハイコントラストじゃないときは独自の色でハイコントラストのときは、ハイコントラストの設定で指定された色を優先（これが WPF のコントロールのデフォの挙動）するようになっています。