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

时间:2013-07-29 15:55:58

标签: wpf c#-4.0 mvvm

我的项目在整个项目中为所有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>

所有WPF Windows引用WindowBase.xaml

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

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

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

Bar1.xaml引用了ProjectTheme.xaml

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

所以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" />

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

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

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

方式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);

方式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);

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

提前致谢。

1 个答案:

答案 0 :(得分:15)

这里有几点需要考虑。

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

您改变主题的整体方法是正确的。最简单的方法是使用Application-scoped resource dictionaries,确保ResourceDictionary中定义了App.xaml。为了添加新资源,我使用了类似于以下内容的代码段:

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

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

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

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