在Silverlight 3中使用主题
Silverlight为我们提供了功能非常强大的样式,却没有提供快速应用样式的方法,例如,我们不能像在WPF中那样根据资源中的样式的TargetType将样式自动应用到所有目标类型的元素上(好消息是,在Silverlight 4中已经可以这么做了)。Silverlight ToolKit(本文示例代码引用的ToolKit版本:Microsoft Silverlight 3 Toolkit November 2009)中提供的默认样式管理器(ImplicitStyleManager)稍微弥补了这一缺憾,通过默认样式管理器,我们可以相对方便的在应用程序中使用主题。本文介绍了在Silverlight中如何使用主题。
前提条件:
在Silverlight 3中使用主题,首先需要在项目中添加对Silverlight ToolKit中的System.Windows.Controls.Theming.Toolkit程序集的引用。如果使用ToolKit中提供的主题(如TwilightBlue主题等),则需要添加相应主题程序集的引用或使用相应主题的样式文件。
使用主题的几种方式:
一、使用主题控件
“主题控件”这种叫法有些别扭,但如果观察一下主题的类继承层次,会发现所有主题均从纯虚类
System.Windows.Controls.Theming.Theme(简称Theme)中继承,而Theme类则直接继承自ContentControl,因此主题确实是一个控件。
使用步骤:
1、添加对相应主题程序集的引用,例如,使用TwilightBlue主题需要添加对System.Windows.Controls.Theming.TwilightBlue程序集的引用。
2、将需要应用主题的元素放到主题控件的内容中。
示例代码:
<UserControl x:Class="ThemeSample.MainPage" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:TwilightBlueTheme="clr-namespace:System.Windows.Controls.Theming;assembly=System.Windows.Controls.Theming.TwilightBlue" > <TwilightBlueTheme:TwilightBlueTheme > <StackPanel x:Name="LayoutRoot" Width="160" Margin="100" > <Button Content="Button" Margin="10" ></Button> <TextBox Text="TextBox" Margin="10"></TextBox> </StackPanel> </TwilightBlueTheme:TwilightBlueTheme> </UserControl>
效果预览:
二、使用ImplicitStyleManager类提供的附加属性
使用该方式时无需添加对相应主题程序集的引用,但是需要使用相应主题提供的样式文件,例如使用TwilightBlue主题时需要System.Windows.Controls.Theming.TwilightBlue.xaml文件,如果已经正确安装了ToolKit,应该能在C:\Program Files\Microsoft SDKs\Silverlight\v3.0\Toolkit\Nov09\Themes\Xaml文件夹找到。
使用步骤:
1、将样式文件添加到项目中,并将生成操作设置为“内容”。
2、对需要应用主题的元素设置附件属性。
示例代码:
<UserControl x:Class="ThemeSample.MainPage" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:Theming="clr-namespace:System.Windows.Controls.Theming;assembly=System.Windows.Controls.Theming.Toolkit" > <StackPanel x:Name="LayoutRoot" Width="160" Margin="100" Theming:ImplicitStyleManager.ApplyMode="Auto" Theming:ImplicitStyleManager.ResourceDictionaryUri= "Themes/TwilightBlue.xaml"> <Button Content="Button" Margin="10" ></Button> <TextBox Text="TextBox" Margin="10"></TextBox> </StackPanel> </UserControl>
ApplyMode属性有三个可选值: None, OneTime和Auto。
None: 不使用样式
OneTime: 在页面加载后接受一次指定的样式
Auto: 在运行时动态添加的控件也将会使用指定样式
效果预览:
三、使用CSharp代码动态改变主题
该方式是第二种方式的CSharp实现,同样不需要相应主题的程序集而只需相应主题的样式文件。为方便演示,示例用户控件中添加了一个ComboBox用来动态改变主题。
示例代码(XAML):
<UserControl x:Class="ThemeSample.MainPage" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:sys="clr-namespace:System;assembly=mscorlib" > <StackPanel x:Name="LayoutRoot" Width="160" Margin="100"> <Button Content="Button" Margin="10" ></Button> <TextBox Text="TextBox" Margin="10"></TextBox> <ComboBox SelectionChanged="ComboBox_SelectionChanged" Margin="10"> <sys:String>ShinyRed</sys:String> <sys:String>TwilightBlue</sys:String> </ComboBox> </StackPanel> </UserControl>
示例代码(cs):
using System; using System.Windows; using System.Windows.Controls; using System.Windows.Controls.Theming; namespace ThemeSample { public partial class MainPage : UserControl { public MainPage() { InitializeComponent(); } private void ComboBox_SelectionChanged(object sender, SelectionChangedEventArgs e) { string themeName = (sender as ComboBox).SelectedItem as string; if (string.IsNullOrEmpty(themeName)) return; Uri uri = new Uri(string.Format("Themes/{0}.xaml", themeName), UriKind.Relative); ImplicitStyleManager.SetResourceDictionaryUri(LayoutRoot, uri); ImplicitStyleManager.SetApplyMode(LayoutRoot, ImplicitStylesApplyMode.Auto); } } }
效果预览:
Silverlight主题存在的缺陷:
ToolKit中提供的主题已经能基本满足一般项目中使用主题的要求,但也存在以下缺陷:
1、通过将主题应用到容器控件上或将容器控件放在主题控件的内容中的方式,可以将主题自动应用到控件的所有子元素,但无法将主题直接应用到所有页面或用户控件中(当然可以将页面或用户控件作为子元素出现)。
2、更糟的是:ChildWindow咋办?
在页面或用户控件中应用的主题不能自动应用到打开的子窗口中,虽然我们可以对子窗口应用主题,但应用主题后的子窗口还是会留下很不协调的边框,如下图:
看来要实现对ChildWindow应用主题,还是要靠我们自己写样式和模板,这无疑给应用主题带来了一些困难。同样存在的好消息是,Silverlight 4中,主题已经可以应用到ChildWindow了,下图是一个Window 7风格的ChildWindow:
以上介绍了如何在Silverlight中使用ToolKit提供的默认主题, 如果想了解自定义主题,请阅读《Silverlight自定义主题》。