0

我们的WPF应用程序有几个 UI 皮肤,可以在运行时切换并应用于特定的框架元素及其子元素。皮肤是经过编译的 xaml资源字典,存储在Theming dll 中,皮肤是通过使用自定义SkinManager类和附加的依赖属性 Skin来实现的,这实际上是通过将皮肤的资源字典添加到目标 FrameworkElement.Resources.MergedDictionaries 来更改皮肤。皮肤字典包含具有 TargetType=" SomeType " 和 BasedOn="{StaticResource {x:Type SomeType }}" 的样式,因此将此样式应用于所有框架元素SomeType,基于 WPF 系统主题的隐式样式。这种方法效果很好,但是当我们尝试将主题引入我们的应用程序时遇到了问题

根据我们的定义,主题 是一种自定义皮肤,适用于整个应用程序 + 特定系统主题(Classic、Luna、Royale、Aero、Aero2(又名 Metro))。它是通过将系统 dll 中的相应资源文件(Aero 主题的 PresentationFramework.Aero 中的 aero.normalcolor.xaml)加载到 Application.Resources.MergedDictionaries 来实现的。如果我们将皮肤添加到此资源字典 - 它会被忽略,因此皮肤将应用于每个活动窗口。这也可以正常工作,但是我们在运行时切换主题时遇到了困难:
如果主题基于相同的系统主题 - 则没有问题,否则我们会得到令人讨厌和不受欢迎的行为:具有应用皮肤的框架元素不会改变通过隐式样式引入的外观(例如,按钮不会改变它的 chrome 和 padding 时皇家主题更改为 aero),此外,如果我们尝试为皮肤和主题存储资源字典的唯一实例,那么我们会遇到具有相同皮肤的主题在视觉上合并到同一主题中的情况:如果我们尝试应用这些主题,则每次都应用首先应用(例如,如果theme1 = royale+ blueskintheme2 = aero+blueskin,那么如果首先应用 theme1 则应用 theme1 和 theme2 在两种情况下都会应用“royale”外观)
是否有任何可能的方法来克服这些问题并在运行时更改 WPF 隐式样式?或者我们没有注意到资源字典的 WPF 机制的一些重要细节?

4

2 回答 2

0

如果我理解你对第一个“皮肤”的问题的理解,即使你设置了另一个,请先尝试清除合并的资源字典......

这里有很多关于在运行时加载资源的主题,例如在运行时 切换 wpf 资源字典

这表明:

ResourceDictionary dic = (ResourceDictionary)XamlReader.Load(fs);
Application.Current.Resources.MergedDictionaries.Clear();
Application.Current.Resources.MergedDictionaries.Add(dic);
于 2013-10-21T16:00:26.130 回答
0

我们已经成功地通过使用 MS.Win32.UXThemeWrapper 类来应用特定的系统主题,这种方式在https://github.com/danielmoore/SystemThemeChange/blob/master/ThemeHelper.cs 通过更改 WPF 的实际系统主题来使用内部和删除隐式样式的 BasedOn 声明。

于 2013-10-29T18:13:05.620 回答