有人要求我们向我们的应用程序添加动态主题切换,但我在弄清楚如何做到这一点时遇到了问题。
这是当前的情况:我们的应用程序有一个具有显式(非隐式)样式的合并资源字典。StaticResource
我们应用程序中的视图通过标记扩展引用这些样式。我们不使用隐式样式的原因是我们对常见类型的控件有多种外观;例如,一个位置的按钮看起来与另一个位置的按钮不同。
所以我们想要做的是创建主题,用一组新的命名样式替换这些命名样式。
方法一
第一次尝试是为每个主题创建资源字典。我从常用字典中删除了其中一种样式,并将它们放在每个主题字典中,使每个副本具有独特的外观,如下所示:
<!-- RedTheme.xaml -->
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
mc:Ignorable="d"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008">
<Style x:Key="HeaderContentStyle" TargetType="ContentControl">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ContentControl">
<Grid Margin="0" Background="Red">
<ContentPresenter Content="{TemplateBinding Content}"/>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>
<!-- BlueTheme.xaml -->
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
mc:Ignorable="d"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008">
<Style x:Key="HeaderContentStyle" TargetType="ContentControl">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ContentControl">
<Grid Margin="0" Background="Blue">
<ContentPresenter Content="{TemplateBinding Content}"/>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>
然后,我添加了代码以从 XAML 动态加载资源字典之一并将其插入到应用程序的合并字典中:
// In App.xaml.cs
var themeUri = new Uri(
"OurApp;component/Themes/RedTheme.xaml", UriKind.Relative);
var resourceInfo = GetResourceStream(themeUri);
using (var stream = resourceInfo.Stream)
{
using (var reader = new StreamReader(stream))
{
var xamlText = reader.ReadToEnd();
var dict = XamlReader.Load(xamlText) as ResourceDictionary;
Resources.MergedDictionaries.Add(dict);
}
}
这在一定程度上奏效了。如果我在启动期间加载了“主题”,则会显示该主题的样式。但是,没有奏效的是在启动后尝试切换到另一个主题。将其他主题主题字典添加到合并字典不会导致 UI 被修改。也没有清除旧的主题词典并添加新的。也没有做任何这些,然后删除根视觉并重新添加它。
方法二
之后,我尝试使用 Silverlight Toolkit 主题模式。我认为这不起作用,因为它旨在切换隐式样式而不是显式样式。我创建了我的 Theme 派生类,设置了它的资源字典 URI,并将该主题添加到了 root visual ContentControl
。但是,当我创建主 UI 类时,找不到 UI 引用的显式样式,因此发生了运行时异常。
因此,我尝试将其中一个主题资源字典加载到应用程序的合并字典中。这允许创建主 UI 类并将其放置在Style
对象内部。但是,Style
资源字典中的显式样式无法覆盖应用程序合并字典中定义的样式。因此,似乎没有任何改变。
当前方法
所以现在我正在考虑第三种方法。它将涉及使用类似这样的附加属性:Theming.Style="StyleName"
. 然后,在应用程序的其他地方,将维护主题名称和样式名称覆盖之间的关联。每当主题更改时,将应用主题的正确样式。
困境
如果已经有一个轮子,我宁愿不重新发明一个轮子。Silverlight 中是否已经内置了允许切换包含显式样式的主题的功能?是否有任何第三方库可以让我做我想做的事?