もくじ
https://tera1707.com/entry/2022/02/06/144447
やりたいこと
Windowsには、ハイコントラストモードというのがあるが、 WPFアプリで、その見た目の変化にアプリのUIを対応させたくなった。
で、対応する際に、
- リソースディクショナリに定義したブラシを、
- 同じKeyで、
- C#のコードから取得する
ということをしたくなった。
そのやり方を調べる。
やったこと
下記のようにする。
- ハイコントラストとそうでないときのResourceDictionaryを作成する
- それぞれに、同じKeyの
<SolidColorBrush>
をつくる - そのBrushを、
FrameworkElement.FindResource
でkey名をもとに取得する - それを、xamlに書いたコントロールに適用する
各モードのResourceDictionaryを作成し、同じKeyのブラシをつくる
WPFでのやり方は、下記の過去記事を参照。
https://tera1707.com/entry/2024/11/16/223546
↑の記事では、KeyのないStyleを定義して、そのTargetTypeのコントロール全部に反映されるようなことをしているが、今回はStyleではなく、ただのブラシをつくる。
ブラシをそれぞれのDictionaryで、同じKeyで定義する。
Dictionary1.xaml
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"> <SolidColorBrush x:Key="MyColor" Color="#FFFF0000"/> </ResourceDictionary>
Dictionary2.xaml
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"> <SolidColorBrush x:Key="MyColor" Color="{DynamicResource {x:Static SystemColors.HotTrackColorKey}}"/> </ResourceDictionary>
C#から、FindResourceでそのブラシを取得する
FindResourceを使って、下記のようにする。
今回は、ボタンをおしたときにブラシを取得し、Ellipse(四角形)のStrokeにそのブラシをセットする。
Windowのコードビハインド内
切替の実施はここでやる
private void Button_Click(object sender, RoutedEventArgs e) { // リソースディクショナリをまず適用して、 ((App)Application.Current).ChangeTheme(themeSwitch); themeSwitch = !themeSwitch; // その中のリソースを、キー名をもとに取得する ellipse.Stroke = (SolidColorBrush)this.FindResource("MyColor"); }
App.xaml.cs
ここがディクショナリ切り替え処理を持ってる
private void Application_Startup(object sender, StartupEventArgs e) { dict = new ResourceDictionary(); Application.Current.Resources.MergedDictionaries.Add(dict); } public void ChangeTheme(bool themeSwitch) { dict!.Source = new Uri($"pack://application:,,,/ResourceDictionary/Dictionary{(themeSwitch ? 1 : 2)}.xaml"); }
前の記事でやった、リソースの切り替えをまずやっている。
使うディクショナリをまずセットしておいて、その中のリソースをとる、という感じ。
(リソースディクショナリを使っていないと、FindResourceでエラーになる。)
これで、リソースディクショナリの中のBrushを取れる。
こううごく
ボタンを押すたびにディクショナリが切り替わって、Ellipseの色が変わる。
SolidColorBrushのColorにSystemColors.XXXXX
を使用する
上のDictionary2.xamlで、SystemColors.HotTrackColorKey
という色を使っている。
こんな感じで書いている。
<SolidColorBrush x:Key="MyColor" Color="{DynamicResource {x:Static SystemColors.HotTrackColorKey}}"/>
この「SystemColors.HotTrackColorKey」というのは、Windowsのハイコントラスト設定画面でいうところの
この色を指している。
ハイコントラストモード時は、ユーザーがこの画面で設定した色を、SystemColors.XXXXXを使って取ってきて、コントロールの色に使う。
今回、このSystemColors.HotTrackColorKey
を、
<SolidColorBrush x:Key="MyColor" Color="{DynamicResource {x:Static SystemColors.HotTrackBrushKey}}"/>
と、間違えて「HotTrackBrushKey」と書いて、下記のような例外を吐かせてしまっていた。
これはおそらく、「HotTrackBrushKey」はブラシそのもののリソースのキーだから、Colorに適用してよいキーじゃないよ!ということだと思う。多分。
その他
ハイコントラストの対応するにあたり、SystemColorsのどの色を使うか?は、要検討。
過去の↓の記事で調べたwinuiのハイコントラスト対応で、winuiのどのSystemColorがどのハイコントラストの色設定に該当するか?を調べた。
https://tera1707.com/entry/2022/04/14/232415
たぶん、そのwinuiの色名に似た色が使われてるんだろうな、とは思う。
参考
FrameworkElement.FindResource(Object) メソッド
WPFでアプリ起動中にResourceDictionaryを切り替えて、見た目を変える過去記事
https://tera1707.com/entry/2024/11/16/223546
WPFのSystemColorsの一覧
https://learn.microsoft.com/ja-jp/dotnet/api/system.windows.systemcolors?view=windowsdesktop-9.0