在 Silverlight 4 中使用显式样式切换运行时主题 [英] Runtime theme switching with explicit styles in Silverlight 4

查看:56
本文介绍了在 Silverlight 4 中使用显式样式切换运行时主题的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

有人要求我们向应用程序添加动态主题切换,但我在弄清楚如何执行此操作时遇到问题.

It's been requested that we add dynamic theme switching to our application, and I'm having problems figuring out how to do this.

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

Here's the current situation: our application has a merged resource dictionary with explicit (not implicit) styles. The views in our application refer to these styles through the StaticResource markup extension. The reason why we're not using implicit styles is that we have multiple looks for common types of controls; for example, buttons in one location look different than buttons in another.

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

So what we are wanting to do is create themes that replace these named styles with a new set of named styles.

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

The first attempt was to create resource dictionaries for each theme. I removed one of the styles from the common dictionaries and placed them in each theme dictionary, giving each copy a distinct look, like this:

<!-- 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 动态加载资源字典之一并将其插入到应用程序的合并字典中:

Then, I added code to dynamically load one of the resource dictionaries from XAML and insert it into the application's merged dictionaries:

// 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 被修改.清除旧的主题词典并添加新的主题词典也没有.也没有执行任何这些操作,然后删除根视觉并重新添加它.

This worked to some extent. If I loaded the "theme" during startup, that theme's style was displayed. However, what didn't work was trying to switch to the other theme after startup. Adding the other theme theme dictionary to the merged dictionaries didn't cause the UI to be modified. Neither did clearing out the old theme dictionary and adding the new one. Neither did doing any of these followed by removing the root visual and re-adding it.

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

After that, I tried using the Silverlight Toolkit pattern of theming. This didn't work, I assume, because it is meant to switch out implicit styles rather than explicit ones. I created my Theme-derived class, set its resource dictionary URI, and added that theme to a root visual ContentControl. Then, however, when I created my main UI class, the explicit style referenced by the UI couldn't be found, so a runtime exception occurred.

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

So then I tried loading one of the theme resource dictionaries into the application's merged dictionaries. This allowed the main UI class to be created and placed inside of the Style object. However, the explicit styles inside of the Style's resource dictionary failed to override the styles defined inside of the application's merged dictionaries. Therefore, nothing appeared to change.

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

So now I'm considering a third approach. It will involve an attached property used something like this: Theming.Style="StyleName". Then, elsewhere in the application, an association between theme names and style name overrides will be maintained. Whenever the theme changes, the right styles for the theme will be applied.

如果已经有轮子,我宁愿不重新发明轮子.Silverlight 中是否已经内置了允许切换包含显式样式的主题的内容?是否有任何第三方库可以让我做我想做的事?

I'd rather not reinvent a wheel if there's already one out there. Is there already something built into Silverlight that allows for switching themes containing explicit styles? Are there any third-party libraries that would let me do what I want?

推荐答案

我不在公司了,所以我不能发布我们最终使用的具体代码,但我们确实采用了附加属性方法.对于需要使用设置为相同值的 Theming.Style 附加属性进行动态换肤的对象,我们替换了对 Style 属性的分配.然后,在我们的资源字典中,我们创建了带有主题名称前缀的样式,例如,在我们曾经有一个StandardButton"样式的地方,我们将创建名称为Blue|StandardButton"和Clean|StandardButton"的其他样式.每当我们切换主题并将它们应用到具有附加属性的元素时,我们的主题引擎就能够查找这些特定于主题的样式.

I'm no longer at the company, so I can't post the specific code we ended up using, but we did go with an attached property approach. We replaced the assignment to the Style property for objects that needed to be dynamically skinned with a Theming.Style attached property set to the same value. Then, in our resource dictionaries, we created styles prefixed with a theme name, for example, where we once had a "StandardButton" style, we would create additional styles with the names "Blue|StandardButton" and "Clean|StandardButton". Our theming engine would then be able to look up those theme-specific styles whenever we switched themes and apply them to the elements with the attached properties.

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

Hopefully this is a helpful approach to others, but preferably there's a library out there that already solves this problem.

这篇关于在 Silverlight 4 中使用显式样式切换运行时主题的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆