WPF动态更改资源文件和主题

Sha*_*awn 10 wpf mvvm c#-4.0

我的项目在整个项目中为所有WPF窗口使用ProjectTheme.xaml文件.ProjectTheme.xaml文件引用样式主题,如下所示

<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>
Run Code Online (Sandbox Code Playgroud)

所有WPF Windows引用WindowBase.xaml

<Window.Resources>
    <ResourceDictionary>
        <ResourceDictionary.MergedDictionaries>
            <ResourceDictionary Source="/MyProject;component/View/WindowBase.xaml"/>
        </ResourceDictionary.MergedDictionaries>
    </ResourceDictionary>
</Window.Resources>
Run Code Online (Sandbox Code Playgroud)

WindowBase.xaml引用自定义标题栏Bar1.xaml

<ResourceDictionary.MergedDictionaries>
    <ResourceDictionary Source="/MyProject;component/Themes/WPFThemes/Bar1.xaml" />
</ResourceDictionary.MergedDictionaries>
Run Code Online (Sandbox Code Playgroud)

Bar1.xaml引用了ProjectTheme.xaml

<ResourceDictionary.MergedDictionaries>
    <ResourceDictionary Source="/MyProject;component/ProjectTheme.xaml"/>
</ResourceDictionary.MergedDictionaries>
Run Code Online (Sandbox Code Playgroud)

所以heriarchy是

  • Window1引用WindowBase.xaml
  • WindowBase引用Bar1.xaml
  • Bar1引用了ProjectTheme.xaml
  • ProjectTheme.xaml引用真实的主题资源文件.

这很好用.现在我想在运行时动态更改项目主题而不退出应用程序.假设我有几个主题样式文件

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

我的问题是,是否可以在运行时动态更新ProjectTheme.xaml文件以更改行

<ResourceDictionary Source="/MyProject;component/Themes/WPFThemes/Customized.xaml" />
Run Code Online (Sandbox Code Playgroud)

<ResourceDictionary Source="/MyProject;component/Themes/WPFThemes/Customized1.xaml" />
Run Code Online (Sandbox Code Playgroud)

实现我的目标?如果是,我该怎么办?如果不是,原因是什么,以及实现目标的最佳(其他)方式是什么?

我尝试了以下但没有一个工作:风格不会改变.

方式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);
Run Code Online (Sandbox Code Playgroud)

方式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);
Run Code Online (Sandbox Code Playgroud)

注意:在我的真实主题样式文件(Customized.xaml ...)中,我使用了动态资源和静态资源的组合.这有关系吗?

提前致谢.

Wil*_*ins 16

这里有几点需要考虑.

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

您改变主题的整体方法是正确的.完成此任务的最简单方法是使用应用程序范围的资源字典,确保ResourceDictionary在您的资源中定义App.xaml.为了添加新资源,我使用了类似于以下内容的代码段:

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

Application.Current.Resources.MergedDictionaries.Add(dict);
Run Code Online (Sandbox Code Playgroud)

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

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