Silverlight 动态改变主题
youhui
不以物喜,不以己悲
Silverlight 动态改变主题
译:http://www.codeproject.com/KB/silverlight/SLDynamicThemes.aspx
文件下载
Download SLDynamicThemes2a_src - 260.29 KB
Download SLDynamicThemes2b_src - 259.6 KB
内容
1. 介绍
2. 如何动态改变主题
3. 在ChildWindow中动态改变主题
4. 总结
介绍
在本文中我将解释如何为您创建一个真正的动态主题的应用程序。创建这个项目,你必须满足以下要求:
1、安装了Visual Studio 2010
2、在CodePlex下载了Silverlight ToolKit 工具包
3、从Microsoft下载最新的Silverlight 4主题文件(JetPack, Accent Color, Windows 7 and Cosmopolitan)。
在下面的截图中我们将测试动态切换主题页面:
如何动态改变主题
我们希望使用已有的主题包让用户较容易的去改变应用程序的外观和良好的用户体验。有2种方法去使用这个主题文件包:
1、 添加主题文件的引用
2、 将原有主题文件添加到项目中
添加主题文件的引用
该技术有以下优势:你只须引用你需要的主题程序集和控件(Core, SDK or Silverlight Toolkit)。不同的控件来自不同的程序集,但你不必引用所有的程序集,只需引用你使用到的程序集和控件。这样会让应用程序包体积更小和更容易浏览项目。缺点就是没有办法修改内置的主题。如果你想创建一个自定义控件或者你想调整现有的一个样式,这就不行了。或者,如果你想用明确的样式重写特定的控件主题与一个明确的风格- 那它就不是一个动态的方式了。
网络上有许多文章在描述了如何使用内置的主题。我们在这里不讨论那些,我们跳到第二个技术。
将原有主题文件添加到项目中
使用这种方法能使我们完全控制了现有的主题。要做到这一点,我们必须将原有Silverlight主题文件添加到项目中。这个方法的主要的问题是,原主题项目中引用了哪些程序集那你现在的这个项目中也必须要引用原主题项目的所有程序集。小应用程序可以接受,但是较大的程序,无疑会增加程序的体积大小(在Silverlight 项目中是无法容忍的)。
新的4个主题有一个层次分明结构,如下所示:
1. Brushes.xaml
(theme brush definitions)
2. Fonts.xaml
(theme font definitions)
3. CoreStyles.xaml
(core Silverlight controls like Button, TextBox, ComboBox, ListBox ...)
4. SDKStyles.xaml
(TabControl, TreeView, DataGrid, DatePicker ...)
5. ToolkitStyles.xaml
(Accordion, ContextMenu, Chart, BusyIndicator ...)
6. Styles.xaml
(styles used for single theme application layout)
此外,我们还增加了Customstyles.xaml在同一主题,用它来定义样式的自定义控件(在这篇文章中,一个页面背景)。
对于每一个主题,有一个容器(一个MergedDictionaries)与上述的嵌入资源作为资源字典。下面是AccentColor.xaml
的截图:
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="/SLDynamicThemes2;component/Assets/Themes/AccentColor/CoreStyles.xaml" />
<ResourceDictionary Source="/SLDynamicThemes2;component/Assets/Themes/AccentColor/SDKStyles.xaml" />
<ResourceDictionary Source="/SLDynamicThemes2;component/Assets/Themes/AccentColor/ToolkitStyles.xaml" />
<ResourceDictionary Source="/SLDynamicThemes2;component/Assets/Themes/AccentColor/Styles.xaml" />
<ResourceDictionary Source="/SLDynamicThemes2;component/Assets/Themes/AccentColor/CustomStyles.xaml" />
</ResourceDictionary.MergedDictionaries>
运行过程中动态改变主题,我们使用工具包中的主题控件。有2个选择,这取决于每个应用程序的要求。第一个是最容易也是最直接是Michael Epner在文章评论给的建议的,适用于整个应用程序的主题的改变。它更友好,因为没必要在最初提出的解决方法中使用主题子窗口。第二个方法-原创-已被用来当局部应用主题(没有改变整个应用程序主题,只改变了局部)。下面你可以找到选项。
2.a.全局应用主题
Download SLDynamicThemes2a_src - 260.29 KB
最简单的解决方案是利用Theme.SetApplicationThemeUri静态方法,它会关注到的改变整个应用程序的主题,不需要额外的解决方法。有没有需要包括主题控制主页布局根或创建任何自定义子使子窗口的主题。只需调用Theme.SetApplicationThemeUri方法,全新的外观会立即可见。void ThemeButton_Click(object sender, RoutedEventArgs e)
{
Button button = sender as Button;
if (button.Tag != null)
{
string themeName = button.Tag.ToString();
if (!String.IsNullOrEmpty(themeName))
{
Uri themeUri = new Uri(string.Format(@"/SLDynamicThemes2;component/Assets/Themes/{0}", themeName), UriKind.Relative);
Theme.SetApplicationThemeUri(App.Current, themeUri);
}
}
}
2.b.局部应用主题
Download SLDynamicThemes2b_src - 259.6 KB运行过程中动态改变主题,我们将使用工具包主题控件并将其添加到页面。在这个例子中,主题控件添加只有MainPage.xaml,它只作用到整个布局控件内部。
<toolkit:Theme x:Name="ThemeContainer" ThemeUri="/SLDynamicThemes2;component/Assets/Themes/JetPack.xaml">
<controls:PageBackground HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
<toolkit:DockPanel LastChildFill="True">
<StackPanel Orientation ="Horizontal" toolkit:DockPanel.Dock="Top"></StackPanel>
<Grid>
<application:Home x:Name="HomePage"/>
</Grid>
</toolkit:DockPanel>
</controls:PageBackground>
</toolkit:Theme>
唯一要做就是修改 Themecontainer的ThemeUri属性。
在MainPage中的四个按钮(见第一张截图)Tag属性定义的是想要应用的主题,确定的主题是应用。当点击时,Themecontainer的ThemeUri也会发生相应的变化,且新的主题将被应用到整个应用程序。
在ChildWindow中动态改变主题
在解释一切关于ChildWindows控件的主题样式前,在这里注意到Liviu Catrina: 现在,只有ChildWindows应用到了主题样式,但是ChildWindow控件本身并没有应用到主题样式。在Silverlight ToolKit有一个限制阻止了ChildWindow控件主题样式(即使原主题包含ChildWinodw控件的样式)。你可以看下由Justin Angel(ToolKit开发人员之一)在官方的论坛作的一个简短的解释。
如果你是上面描述的第一种方法- 2.a 全局主题应用,就没必要担心主题没应用到ChildWindow。主题将被自动应用到任何子窗口应用程序。如果是- 2.b局部应用主题,下面准备将我们的ChildWindow控件以使它支持主题。
如果我们仔细观察ChildWindow内部,会发现ChildWindow和它里面的所有控件都没有应用到主题样式。下一步,我们将提出一个解决方案,确保主题是也适用于ChildWindow(见下面的截图):
ChildWindow主题可以启用通过创建一个自定义类(CustomChildWindow在我们的例子里面),我们将重载
OnApplyTemplate
()
方法。我们希望所有的ChildWindow都用到CustomChildWindow里面的一个主题控件叫做ThemeContainer。这个意思就是记住您当前的应用程序ThemeUri在任何ChildWindow显示时使用它。
public class CustomChildWindow : ChildWindow
{
public override void OnApplyTemplate()
{
base.OnApplyTemplate();
Theme themeContainer = (Theme)(this).FindName("ThemeContainer");
if (themeContainer != null)
{
App app = (App)App.Current;
MainPage mainPage = app.RootVisual as MainPage;
themeContainer.ThemeUri = mainPage.CurrentThemeUri;
}
}
}
<toolkit:Theme x:Name="ThemeContainer">
<Grid x:Name="LayoutRoot" HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
<appControls:PageBackground HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
<StackPanel HorizontalAlignment="Center" VerticalAlignment="Center">
<TextBlock Name="ThemeNameTextBlock" Loaded="ThemeNameTextBlock_Loaded"></TextBlock>
</StackPanel>
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center" VerticalAlignment="Bottom">
<Button Name="OK" Click="Button_Click" Margin="0,0,10,0">OK</Button>
<Button Name="Cancel" Click="Button_Click" Margin="0,0,10,0">Cancel</Button>
</StackPanel>
</appControls:PageBackground>
</Grid>
</toolkit:Theme>
ThemeContainer控件包含一切到ChildWindow中并且里面的任何控件都将继承各自的样式在当前的应用程序。
结论
在本文中我给出了一个详细的方法让您在应用程序可以启用动态主题。它给你完全掌控现有的主题且让您在自定义控件中扩展它们。
我想说,谢谢大家的建议和意见。是你们的帮助改进的原始文件使它更好。
感谢作者:rzvdaniel comes from Romania
翻译水平有限,敬请谅解,错误之处还请各位斧正。 谢谢!
http://www.cnblogs.com/youhui/archive/2012/01/08/2316222.html