在Silverlight 4中使用显式样式进行运行时主题切换

时间:2010-09-22 00:37:08

标签: silverlight silverlight-4.0 themes styles resourcedictionary

我们已经要求我们将动态主题切换添加到我们的应用程序中,并且我在确定如何执行此操作时遇到了问题。

以下是当前的情况:我们的应用程序具有带有显式(非隐式)样式的合并资源字典。我们的应用程序中的视图通过StaticResource标记扩展来引用这些样式。我们之所以不使用隐式样式,是因为我们对常见的控件类型有多种外观;例如,一个位置的按钮看起来与另一个位置的按钮不同。

所以我们想要做的是创建用一组新的命名样式替换这些命名样式的主题。

方法1

第一次尝试是为每个主题创建资源词典。我从常用字典中删除了其中一种样式,并将它们放在每个主题字典中,为每个副本提供了独特的外观,如下所示:

<!-- 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被修改。也没有清除旧的主题词典并添加新的主题词典。也没有做过这些,然后删除root视觉并重新添加它。

方法2

之后,我尝试使用Silverlight Toolkit模式的主题。我认为这不起作用,因为它意味着切换出隐式样式而不是显式样式。我创建了我的Theme派生类,设置了它的资源字典URI,并将该主题添加到根视觉ContentControl。然而,当我创建主UI类时,无法找到UI引用的显式样式,因此发生了运行时异常。

然后我尝试将其中一个主题资源字典加载到应用程序的合并字典中。这允许创建主UI类并将其放在Style对象内。但是,Style的资源字典中的显式样式无法覆盖应用程序的合并字典中定义的样式。因此,似乎没有任何改变。

当前方法

所以现在我正在考虑第三种方法。它将涉及使用类似这样的附加属性:Theming.Style="StyleName"。然后,在应用程序的其他位置,将保持主题名称和样式名称覆盖之间的关联。每当主题发生变化时,都会应用主题的正确样式。

困境

如果已经有一个轮子,我宁愿不重新发明轮子。 Silverlight中是否已经内置了允许切换包含显式样式的主题的内容?是否有任何第三方图书馆可以让我按照自己的意愿行事?

1 个答案:

答案 0 :(得分:4)

我不再在公司工作,因此我无法发布我们最终使用的特定代码,但我们确实采用了附加属性方法。我们将赋值替换为Style属性,用于需要动态设置皮肤的对象,并将Theming.Style附加属性设置为相同的值。然后,在我们的资源字典中,我们创建了带有主题名称的样式,例如,我们曾经有过“StandardButton”样式,我们会创建名称为“Blue | StandardButton”和“Clean | StandardButton”的其他样式。每当我们切换主题并将它们应用于具有附加属性的元素时,我们的主题引擎就可以查找这些特定于主题的样式。

希望这对其他人来说是一种有用的方法,但最好还有一个已经解决了这个问题的库。