コントロールのマウスオーバー時等の色を変えたい

WInUI3関連記事

https://tera1707.com/entry/2022/02/06/144447#WinUI3

やりたいこと

WinUI3 各コントロールの見た目の色をいじりたい。

例えば、ボタンのマウスオーバー時の色を自分の好きな色に変えたい。
そのやり方を調べたときに辿った道順をメモする。

色の出どころがどこなのか?調べる

まずは、ボタンのマウスオーバー時の色がどこから来てるのか?を調べる。

C:\Program Files (x86)\Windows Kits\10\DesignTime\CommonConfiguration\Neutral\UAPに、Windowsのバージョンごとに、標準のResourceDictionaryがある。

f:id:tera1707:20220404223749p:plain

おそらく、マウスオーバー時の色を変えたいくらいであれば、どのバージョンのResourceDictionraryを見ても同じなので、 一旦10.0.19041.0を開く。

その中の\10.0.19041.0\Generic\generic.xamlを開く。

さらにその中の6189行目あたりに、ボタンのスタイルが定義してある。 さらにさらにその中の6203行目あたりに、ボタンのテンプレートが定義してある。

f:id:tera1707:20220404223842p:plain

今回は、マウスオーバー時の色を変えたいだけなので、マウスオーバーの時の色変化は標準でどうやってるか?を見てみる。 →<VisualState x:Name="PointerOver">あたりを見る。

そうすると、そこには下記のようなことが書いてある。

  • BackgroundButtonBackgroundPointerOver にする
  • BorderBrushButtonBorderBrushPointerOver にする
  • ForegroundButtonForegroundPointerOver にする

f:id:tera1707:20220404223927p:plain

例えばその中の ButtonBackgroundPointerOver(マウスオーバー時のボタンの背景の色) が実際何色かを見ていくと、

  • <StaticResource x:Key="ButtonBackgroundPointerOver" ResourceKey="SystemControlBackgroundBaseLowBrush" />とあり、
    • <SolidColorBrush x:Key="SystemControlBackgroundBaseLowBrush" Color="{ThemeResource SystemColorButtonFaceColor}" /> とある。

<StaticResource x:Key="ButtonBackgroundPointerOver" ResourceKey="SystemControlBackgroundBaseLowBrush" />はgeneric.xamlの中に3つあり、 それぞれ<ResourceDictionary x:Key="Default"><ResourceDictionary x:Key="HighContrast"><ResourceDictionary x:Key="Light">の中にある。 そのそれぞれが、ライト、ダーク、ハイコントラスト時の色の定義っぽい。

このSystemColorButtonFaceColorは、下記のシステムカラーの定義の中にあった。 C:\Program Files\Microsoft Visual Studio\2022\Community\DesignTools\SystemThemes\WinUI\SystemColors.xaml

私のVS2022がCommunityなので上記のフォルダだが、Professional版等、ほかのエディションだったらまた別のフォルダにあると思われる。

色は<Color x:Key="SystemColorButtonFaceColor">#FFF0F0F0</Color>とあった。

ここが、色の出所っぽい。

実際に色を変えてみる

じゃあその#FFF0F0F0を変えればいいのかなと思ったが、

SystemColorButtonFaceColorのようなSystemColors.xamlの中の色の定義は、自分のアプリのリソースではないので変えられなさそう。
SystemControlBackgroundBaseLowBrushは、それを使っている個所が多数あるので、変えることができたとしても変えたくない。

  • ButtonBackgroundPointerOverの色を上書きして、色を変えてみる。

まずは、簡易的に、メイン画面のリソースに、上書した色を書いてみる。
今回は、黄色にしてみた。

<Window
    x:Class="DefaultControlTemplateTest.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:DefaultControlTemplateTest"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d">   

    <StackPanel Orientation="Horizontal" HorizontalAlignment="Center" VerticalAlignment="Center">
        <StackPanel.Resources>
            <SolidColorBrush x:Key="ButtonBackgroundPointerOver" Color="Yellow" />
        </StackPanel.Resources>
        <Button x:Name="myButton" Click="myButton_Click">Click Me</Button>
    </StackPanel>
</Window>

これで、マウスオーバー時、

f:id:tera1707:20220404223037p:plain

のような感じになった。

その後

あとは、そのほかのイベント(Disable時やボタン押下時)のときにも同じように、標準の色変化と違う色変化をしたければ、<VisualState x:Name="Pressed"><VisualState x:Name="Disabled">のときの色を上書してやればOK。

220411追記 SystemAccentColorLight1,2,3,SystemAccentColorDark1,2,3の正体

Fluent Xaml Theme Editorで作ったリソースディクショナリの中に、掲題のようなリソースがあったのだが、これがなんだかよくわかってなかった。
→下記に書いてあった。

docs.microsoft.com

Fluent Xaml Theme Editorの吐いたリソースディクショナリのコレ

f:id:tera1707:20220411220543p:plain

を見て、勝手に「Lightとついてる奴は、ライトテーマを選んでいるときに、アクセントカラーとして使われる奴なんだろうな。(でも、<ResourceDictionary x:Key="Light">のなかにも‘#FF0064BE‘やDark2,Dark3があるな、どういう意味だろう?)となっていた。

これはそういう意味ではなく、

キー名 意味
SystemAccentColorDark3 SystemAccentColorよりとても暗い色
SystemAccentColorDark2 SystemAccentColorより暗い色
SystemAccentColorDark1 SystemAccentColorよりちょっと暗い色
SystemAccentColor 元のアクセントカラーの値
SystemAccentColorLight1 SystemAccentColorよりちょっと明るい色
SystemAccentColorLight2 SystemAccentColorより明るい色
SystemAccentColorLight3 SystemAccentColorとても明るい色

という意味らしい。だから、下記のようなxamlを書いて、

 <StackPanel Orientation="Horizontal">
     <Grid Width="50" Height="50" Background="{ThemeResource SystemAccentColorDark3}"/>
     <Grid Width="50" Height="50" Background="{ThemeResource SystemAccentColorDark2}"/>
     <Grid Width="50" Height="50" Background="{ThemeResource SystemAccentColorDark1}"/>
     <Grid Width="50" Height="50" Background="{ThemeResource SystemAccentColor}"/>
     <Grid Width="50" Height="50" Background="{ThemeResource SystemAccentColorLight1}"/>
     <Grid Width="50" Height="50" Background="{ThemeResource SystemAccentColorLight2}"/>
     <Grid Width="50" Height="50" Background="{ThemeResource SystemAccentColorLight3}"/>
 </StackPanel>

windowsのアクセントカラーの設定を青にしていると、 f:id:tera1707:20220411221214p:plain

こうなる

f:id:tera1707:20220411221236p:plain

緑にしてると

f:id:tera1707:20220411221302p:plain

こうなる。

で、Fluent Xaml Theme Editorで作ったリソースディクショナリのように、自分のコードの中に‘#FF1D85D7‘などを書いていると、Windowsのアクセントカラー設定の色を上書きする形になり、Windowsのアクセントカラーの設定によらず、コードの中の上書した値が使われる形になる。

だから、アクセントカラーの色を使っているコントロールの色を、ユーザーのアクセントカラーの設定に左右されない色にしたいときは、これを上書き(オーバーライド)すればよいかも。
(もしくは、style等を使ってアクセントカラーを使うのをやめさせるか)

220411追記 {StaticResource 色のキー名} と {ThemeResource 色のキー名} の違い

StaticResource だと、起動時に一回だけリソースが読み込まれる。
ThemeResourceだと、テーマ変更時に再度読み込まれる。

docs.microsoft.com

ためしに、下記のようなxamlを書いてみる。

Dark1,2,3だけがStaticResourceを使っていて、SystemAccentColorとLight1,2,3がThemeResourceを使っている。

<StackPanel Orientation="Horizontal">
    <Grid Width="50" Height="50" Background="{StaticResource SystemAccentColorDark3}"/>
    <Grid Width="50" Height="50" Background="{StaticResource SystemAccentColorDark2}"/>
    <Grid Width="50" Height="50" Background="{StaticResource SystemAccentColorDark1}"/>
    <Grid Width="50" Height="50" Background="{ThemeResource SystemAccentColor}"/>
    <Grid Width="50" Height="50" Background="{ThemeResource SystemAccentColorLight1}"/>
    <Grid Width="50" Height="50" Background="{ThemeResource SystemAccentColorLight2}"/>
    <Grid Width="50" Height="50" Background="{ThemeResource SystemAccentColorLight3}"/>
</StackPanel>

これを、アクセントカラーで青色を選択した状態で、上記コードを起動すると下記のようになり、

f:id:tera1707:20220411221236p:plain

そのままアプリ起動した状態でアクセントカラーを緑に変更すると、下図のようになる。 (Dark1,2,3の方が、OSのアクセントカラーの変更についてきていない)

f:id:tera1707:20220411223934p:plain

220411追記 私と同じで、ブラシがたくさんありすぎて迷い込んだ方のissue

ブラシがたくさんありすぎてわけわからないので一覧が欲しい、とこの方も言っている様子。

github.com

まったく同じ気持ちだったのだが、ここで言われているのが、

  1. コントロールのテーマブラシとして名前の付いたブラシは1000を超える数がある。
  2. システムのブラシと色は約150〜200ある。
  3. ただし実際の色は、25種類前後だけ。

とのこと。

①が、C:\Program Files (x86)\Windows Kits\10\DesignTime\CommonConfiguration\Neutral\UAP<sdkVersion>\10.0.19041.0\Generic\themeresources.xamlの2090行目より下にあるSliderContainerBackgroundのような、コントロールの種類名がキーについたブラシのことっぽい。

f:id:tera1707:20220411232159p:plain

f:id:tera1707:20220411234501p:plain

②が、themeresources.xamlの上の方にあるSystemなんとかかんとかというColorと、SystemControlなんとかかんとかという名前のSolidColorBrushっぽい。(10.0.22000.0のthemeresources.xamlの204~327行目あたり)

f:id:tera1707:20220411232237p:plain

そのすぐ上あたりに、そのブラシで使っている色(Color)が定義されてる。(SystemAccentColorなど、特別な奴は、③の中にある)

f:id:tera1707:20220411234903p:plain

③が、‘C:\Program Files\Microsoft Visual Studio\2022\Community\DesignTools\SystemThemes\WinUI\SystemColors.xaml‘ にある色とブラシのことっぽい。

f:id:tera1707:20220411232306p:plain

220411追記 で、結局winui3でテーマ対応(ダーク、ライト、ハイコントラスト)対応するにはどうしたらいいのか?

考え中...

一番上に書いたやり方で、①をオーバーライドしてやれば、コントロールごとの色を変えることは可能だった。
では、もっと広い範囲の色を一気に変えたいとき等に、②③はオーバーライドできるのか?ためす。

参考

テーマの色を変えたいときのガイドライン。 デフォルトのリソースディクショナリがどこにあるか?や、色(をはじめとしたリソース)の変え方が書かれてる

docs.microsoft.com

SystemColorの定義が書かれていそうな個所を探していたときに見つけた WPFでの」 その辺がありそうなフォルダについて書かれた公式doc。 この辺をいろいろ見ていたら「winui」というフォルダがあり、そこを見たら、上で書いたフォルダが見つかった。
(WinUI3でSystemColorsの定義が書かれてそうなファイルについての公式docは見つけられなかった)

docs.microsoft.com

WinUI3のコントロールの見本市アプリ。

WinUI 3 Controls Gallery を入手 - Microsoft Store ja-JP