アプリ自身で自分のテーマ(ダーク/ライト)を変更する

WinUI3関連記事
https://tera1707.com/entry/2022/02/06/144447#WinUI3

やりたいこと

以前、アプリ画面上にあるコントロール類を、テーマ(ダーク/ライト/ハイコントラスト)に沿った色でにするということをした。

tera1707.com

今回は、アプリ自身で、自分のテーマを変更できるということを下記の動画を見て知ったので、それを試してみる。

www.youtube.com

前提

  • Windows10 Home 21H1 19043.1706
  • VisualStudio2022 Community 17.1.4
  • WinUI3.0
  • Windows App SDK 1.0
  • 2022年5月の時点で調査実施

サンプルコード

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

    <Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
        <StackPanel Orientation="Vertical" HorizontalAlignment="Center" VerticalAlignment="Center">
            <Button Click="myButton_Click">今のテーマを取得</Button>
            <Button Click="Button_Click_Light">テーマを切り替え(ライト)</Button>
            <Button Click="Button_Click_Dark">テーマを切り替え(ダーク)</Button>
            <Button Click="Button_Click_Default">テーマを切り替え(Default)</Button>
            <TextBlock Name="tbText"/>
        </StackPanel>
    </Grid>    
</Window>
using Microsoft.UI.Xaml;
using System.Diagnostics;

namespace ThemeChangeJikken
{
    public sealed partial class MainWindow : Window
    {
        public MainWindow()
        {
            this.InitializeComponent();
        }

        // 今のテーマを取得
        private void myButton_Click(object sender, RoutedEventArgs e)
        {
            if (this.Content is FrameworkElement fe)
            {
                Debug.WriteLine(fe.ActualTheme.ToString());
                tbText.Text = fe.ActualTheme.ToString();
            }
        }

        // テーマを設定(ダーク)
        private void Button_Click_Dark(object sender, RoutedEventArgs e)
        {
            if (this.Content is FrameworkElement fe)
            {
                fe.RequestedTheme = ElementTheme.Dark;
            }
        }
        // テーマを設定(ライト)
        private void Button_Click_Light(object sender, RoutedEventArgs e)
        {
            if (this.Content is FrameworkElement fe)
            {
                fe.RequestedTheme = ElementTheme.Light;
            }
        }
        // テーマを設定(PCのテーマ設定に合わせる)
        private void Button_Click_Default(object sender, RoutedEventArgs e)
        {
            if (this.Content is FrameworkElement fe)
            {
                fe.RequestedTheme = ElementTheme.Default;
            }
        }
    }
}

動かしたのがこちら

コードについて

WindowのContentのActualThemeを見ると、今のテーマがわかる。

RequestedThemeに設定したいテーマを入れると、テーマを変更できる。

背景だけは、Fluent-xaml-theme-editorのreadmeにある通り、背景の色は、自分で設定しないといけない。今回は、「ApplicationPageBackgroundThemeBrush」を一番外のstackpanelにセットした。 (Lastly, don’t forget to set the background color of your page to the RegionColor・・・・のあたり)

※「ApplicationPageBackgroundThemeBrush」は、C:\Program Files (x86)\Windows Kits\10\DesignTime\CommonConfiguration\Neutral\UAP\10.0.22000.0\Generic\generic.xamlに定義されてる。

アプリのテーマ/コントロールのテーマ

今回やっているのは「コントロールのテーマ」の変更なので、「アプリ全体のテーマ」とはまた別っぽい。

なので、今回「Window」というコントロールのテーマを変えたので、例えばWindowの中のある一つのボタンだけのテーマを変える、とかもできる。 画面内のボタンのテーマだけを変えてみたのがコレ。

あと、まだ未検証なのだが、「アプリ全体のテーマ」を変えるには、Application.Current.RequestedTheme)というのを使うっぽい。

「ElementTheme Enum の Default」がなんなのか?

Windowsでは、RequestedThemeをDefaultに設定すると、常に「Dark」で、Windows Phoneでは、デフォルト値を使用すると、ユーザーが設定したシステムテーマになるとある。(ここでの「Windows」はデスクトップアプリで、「Windows Phone」は、パッケージしたアプリかな) →こちら

今回実験した、「前提」に書いた環境で試した限り、「Default」は、Windowsの「色」の設定の値をとってきている。

参考

アプリのテーマを変えれると知ったきっかけ動画

https://www.youtube.com/watch?v=w2XdbyNrXBQ

FrameworkElement.RequestedTheme Property

https://docs.microsoft.com/ja-jp/windows/winui/api/microsoft.ui.xaml.frameworkelement.requestedtheme?view=winui-3.0&viewFallbackFrom=winui-2.5

ElementTheme Enum

https://docs.microsoft.com/ja-jp/uwp/api/windows.ui.xaml.elementtheme?view=winrt-14393