アプリ起動中にResourceDictionaryを切り替えて、見た目を変える

もくじ
https://tera1707.com/entry/2022/02/06/144447

やりたいこと

以前の記事で、アプリ起動時にResourceDictionaryを切り替えるということをした。

qiita.com

今回は、アプリがすでに起動してウインドウが出ている最中に、ResourceDictionaryを切り替えて、見た目を変更するということをしたい。

やり方

やること自体は↑の以前の記事と一緒なのだが、それをウインドウの中から呼んでやる。

つまり、↑の記事のコードで行っていた、Appクラスで行った下記の処理を、ウインドウの中で行ってやる。

サンプルコード

App.xaml.cs

スタートアップのコード。

ここで、ResourceDictionaryを切り替える処理を持つ。

using System.Windows;

namespace ResourceDicJikken;

public partial class App : Application
{
    private ResourceDictionary? dict;

    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");
    }
}

MainWindow.xaml.cs

ウインドウ側のコード。

ここで、Appクラスが持っているResourceDictionary切り替えのためのメソッドを呼ぶ。

using System.Windows;

namespace ResourceDicJikken
{
    public partial class MainWindow : Window
    {
        bool themeSwitch = false;

        public MainWindow()
        {
            InitializeComponent();
        }

        private void Button_Click(object sender, RoutedEventArgs e)
        {
            ((App)Application.Current).ChangeTheme(themeSwitch);
            themeSwitch = !themeSwitch;
        }
    }
}

Dictionary1.xaml、2.xaml

切替をする2つのResourceDictionaryのファイル。

それぞれ背景の色だけ異なる色を定義している。

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
    <Style TargetType="Button">
        <Setter Property="Background" Value="Purple"/>
    </Style>
</ResourceDictionary>
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
    <Style TargetType="Button">
        <Setter Property="Background" Value="Yellow"/>
    </Style>
</ResourceDictionary>

地味にハマるポイント

ResourceDictionaryを切り替える処理には、

public void ChangeTheme(bool themeSwitch)
{
    dict!.Source = new Uri($"pack://application:,,,/ResourceDictionary/Dictionary{(themeSwitch ? 1 : 2)}.xaml");
}

と書いているのだが、このアドレス?ファイルのパス?みたいな部分、どう書くのコレ?となる。

ココの部分の書き方は、msの↓のdocに書いてあった。

learn.microsoft.com

VS2022のソリューションエクスプローラーで今回のslnの構成を見ると、こうなっている。

で、msのdocによると、

となっていて、今回の構成だと、「ResourceDictionary」というサブフォルダに入れているので、結果、

pack://application:,,,/ResourceDictionary/Dictionary1.xaml

という指定の仕方になる。

参考

Pack URIs in WPF

https://learn.microsoft.com/en-us/dotnet/desktop/wpf/app-development/pack-uris-in-wpf?view=netframeworkdesktop-4.8#local-assembly-resource-file
>「Local Assembly Resource File」 の部分。

Pack URIみたいな似たようなものをWinUIについて調べたときの記事。
WPFとWinUI3ではまた書き方が違うらしい。

https://tera1707.com/entry/2022/05/17/235117