10

My project uses a ProjectTheme.xaml file for all WPF windows through out the project. The ProjectTheme.xaml file references a style theme as follows

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
    <ResourceDictionary.MergedDictionaries>
        <!-- In order to modify the project's theme, change this line -->
        <ResourceDictionary Source="/MyProject;component/Themes/WPFThemes/Customized.xaml" />
    </ResourceDictionary.MergedDictionaries>
</ResourceDictionary>

All WPF Windows references WindowBase.xaml

<Window.Resources>
    <ResourceDictionary>
        <ResourceDictionary.MergedDictionaries>
            <ResourceDictionary Source="/MyProject;component/View/WindowBase.xaml"/>
        </ResourceDictionary.MergedDictionaries>
    </ResourceDictionary>
</Window.Resources>

WindowBase.xaml references customized titlebar Bar1.xaml

<ResourceDictionary.MergedDictionaries>
    <ResourceDictionary Source="/MyProject;component/Themes/WPFThemes/Bar1.xaml" />
</ResourceDictionary.MergedDictionaries>

Bar1.xaml references ProjectTheme.xaml

<ResourceDictionary.MergedDictionaries>
    <ResourceDictionary Source="/MyProject;component/ProjectTheme.xaml"/>
</ResourceDictionary.MergedDictionaries>

So the heriarchy is

  • Window1 references WindowBase.xaml
  • WindowBase references Bar1.xaml
  • Bar1 references ProjectTheme.xaml
  • ProjectTheme.xaml reference the real theme resource file.

This works fine. Now I want to dynamically change the project theme at run time without quitting the app. Assuming that I have several theme style files

  • Customized.xaml
  • Customized1.xaml
  • Customized2.xaml

My question is if it possible to dynamically update ProjectTheme.xaml file at run time to change the line from

<ResourceDictionary Source="/MyProject;component/Themes/WPFThemes/Customized.xaml" />

to

<ResourceDictionary Source="/MyProject;component/Themes/WPFThemes/Customized1.xaml" />

to achieve my objective? If yes, how do I do it? If no, what is the reason and what is the best (other) way to achieve my purpose?

I have tried the following but none of them work: the style does not change.

way 1

Application.Current.Resources.MergedDictionaries.Clear();
Uri NewTheme = new Uri(@"/MyProject;component/Themes/WPFThemes/Customized2.xaml", UriKind.Relative);
ResourceDictionary dictionary = (ResourceDictionary)Application.LoadComponent(NewTheme);
Application.Current.Resources.MergedDictionaries.Add(dictionary);

way 2

Application.Current.Resources.MergedDictionaries.RemoveAt(0);
Uri NewTheme = new Uri(@"/MyProject;component/Themes/WPFThemes/Customized2.xaml", UriKind.Relative);
ResourceDictionary dictionary = (ResourceDictionary)Application.LoadComponent(NewTheme);
Application.Current.Resources.MergedDictionaries.Insert(0, dictionary);

Note: In my real theme style files (Customized.xaml...) I used a combination of dynamic resource and static resource. Does that matters?

Thanks in advance.

4

1 回答 1

17

这里有几件事需要考虑。

首先,用 定义的任何内容StaticResource都不会随着更改而更新。如果您希望控件支持在运行时更改主题,则需要使用DynamicResource它知道查找更改。

您更改主题的总体方法是正确的。完成此任务的最简单方法是使用应用程序范围的资源字典,确保您ResourceDictionaryApp.xaml. 为了添加新资源,我使用了类似于以下内容的片段:

ResourceDictionary dict = new ResourceDictionary();
dict.Source = new Uri("MyResourceDictionary.xaml", UriKind.Relative);

Application.Current.Resources.MergedDictionaries.Add(dict);

您可能会感到困惑的部分是在基类中使用资源时。当您在类中定义资源时,该资源将是该类型实例的本地资源。想想 XAML 在类上编译成它自己的InitializeComponent()方法,这意味着您不能更改原始 XAML 并期望更改适用于所有实例。同样,更改类实例上的资源不会影响其他实例。

由于您的问题确实包含两个独立的问题(应用程序主题和更改控制资源),我将专注于确保您的应用程序资源正确更新和使用DynamicResource,希望我提供的信息足以理解为什么某些其他资源可能不会还在更新。

于 2013-07-29T16:16:30.503 回答