科技行者

行者学院 转型私董会 科技行者专题报道 网红大战科技行者

知识库

知识库 安全导航

至顶网软件频道基础软件在 WPF 中创建可换肤的用户界面

在 WPF 中创建可换肤的用户界面

  • 扫一扫
    分享文章到微信

  • 扫一扫
    关注官方公众号
    至顶头条

这篇文章讨论的是在WPF中如何创建可以在运行时”换肤”的用户界面的一些基础知识,我们将验证WPF对用户界面”皮肤”的支持……

作者:周银辉 来源:博客园 2007年11月19日

关键字: WPF 可换肤 用户界面

  • 评论
  • 分享微博
  • 分享邮件
这篇文章讨论的是在WPF中如何创建可以在运行时换肤的用户界面的一些基础知识,我们将验证WPF对用户界面皮肤的支持,并通过一个简单的示例程序来展示如何使用这些特性。

  背景

  当皮肤这个术语被应用到用户界面中来时,就是指被运用于用户界面上的所有界面元素的可视化样式.一个可换肤的用户界面既可以是在编译时也可以是在运行时被定制(制定皮肤).WPF为用户界面的"换肤"提供了强大的支持.

  对于一个软件来说在很多情形下"换肤"也许将变得非常重要.它可以被用来允许最终用户根据个人审美观念来定制自己的软件界面.还有一种情形也许会用到"换肤",就是当一个公司开发的应用程序被分发成多种客户端,也许每个客户端得拥有它自己的Logo,颜色,字体等等,如果这些程序被有意地设计成可换肤的话,那么只需要付出一点点的努力就可以很轻松的完成这项任务了.

  三大基础

  解决这一难题需要三大基础,在该部分我们只对它们做一个简要的介绍,可以参考本文的结尾处的"外部链接"部分以获得更多相关信息.如果你对"层次型资源","合并的资源字典"以及"动态资源"比较熟悉的话,你可以跳过该部分.

  层次型资源

  为了实现软件"换肤",你必须明白WPF的资源系统是如何运作的.在WPF中有很多类型都拥有一个ResourceDictionary类型的公开属性Resources,该字典包含了一个"键-值"对列表,其中"键"可以是任意类型的对象,其"值"就是一个资源(“值"也可以是任意类型的对象).大多数时候我们放入资源字典中的"键"都是string类型的对象,而有时也可能是其他类型.所有的资源都被存放到这样的资源字典中,而资源查找程序正是使用它们来查找所需的资源.

  在应用程序中,资源是按照一种层次关系被组织在一起的.当定位资源(比如画刷,样式,数据模板或气体任意类型的对象)时,软件就会执行一个导航于这个层次组织间的查找程序来查找与指定"键"相对应的资源.

  它(资源查找程序)会首先检查需求该资源的元素自己所拥有的那些资源,如果没有找到,则它会检查该元素的"父元素",看该"父元素"是否拥有所需的资源.如果"父元素"也没有所需的资源,则它会继续沿着"元素树"向上检查该元素的每一个"祖先".如果仍然没有找到,则它最终会向Application对象询问该资源,在本文中我们可以忽略在那之后还会发生什么.

  合并的资源字典

  ResourceDictionary类中有一个属性允许你从其它的ResourceDictionary实例来合并资源字典,这就像集合的"并集".这个属性名叫MergedDictionaries,其类型为Collection.下面这段话是SDK文档中用于解释资源合并时的域规则:

  在合并字典中的资源仅仅当它们被合并到主资源字典域中之后才在资源查找域中占有一个位置.尽管在独立的字典中其资源"键"必须是互不相同的,但在合并字典中一个"键"却可能出现多次.因此,被返回的资源就来自于被合并的资源字典集合中的最后一个字典.如果这些被合并的资源字典是用XAML定义的话,那么它们在合并字典中的顺序就于它们在XAML语言中被标记的顺序一致.如果一个"键"既包含于主字典又包含于其它被合并的字典,那么在主字典中的资源将被返回.这些规则既适合动态资源引用也适合于静态资源引用.

  转到本文末尾处的"外部链接"部分你可以找到关于资源合并的帮助页链接.

  动态资源引用

  解决这一难题(软件换肤)的最后一个基础点是通过元素的属性动态地访问可视化资源的这一机制,这也就是扩展标记DynamicResource所做的事情.动态资源引用就向数据绑定一样,当资源在运行时被替换后那些使用该资源的属性将被赋予新的资源.

  比如说我们有一个TextBlock对象,它的Background属性必须被设定为有当前皮肤决定的任意的Brush,我们可以为该TextBlock对象的Background属性建立一个动态资源引用,当在运行是软件的皮肤被更换后,与之相应的画刷就将被应用于该TextBlock.动态资源引用将会自动地用新画刷来更新TextBlock对象的Background属性.

  正如下面的XAML所描述的一样:

以下是引用片段:
<TextBlock Background="{DynamicResource myBrush}" Text="Whatever..." />

  转到本文末尾处的"外部链接"部分参考在代码中是如何做到的.

  应用三大基础

  每个皮肤的资源都被放到独立的ResourceDictionary中,它们都属于自己的XAML文件.在运行时我们可以加载一个包含的所有皮肤所需资源的ResourceDictionary(此后我们称之为"皮肤字典"),并将它插入到MergedDictionaries 中(其为Application对象的ResourceDictionary),通过将皮肤字典插入到应用程序资源中,应用程序的所有的元素都可以使用该皮肤字典中所包含的资源了.

  界面上所有支持换肤的元素都应该通过动态资源引用来引用皮肤资源,这就使得我们可以在运行时进行换肤以及让这些元素拥有新的皮肤资源.

  最简单的完成这项任务的方式是让元素的Style属性被指定为动态资源引用.通过使用元素的Style属性,我们可以让皮肤字典包含那些可以设置任意个属性的Style,这就比从皮肤字典中为每一个单独的属性设置动态资源引用更容易编写和维护代码.

  示例程序是什么样子的

  我们可以在本文的顶部位置下载到这个示例程序,其包含了一个可以设置三种皮肤的简单窗体.当你使用默认皮肤启动程序时,其如图所示:

skinedApp2.png

  当你右击窗体的任意位置时,会弹出一个上下文菜单允许你更换皮肤,如下图所示:

skinedApp3.png

    • 评论
    • 分享微博
    • 分享邮件
    邮件订阅

    如果您非常迫切的想了解IT领域最新产品与技术信息,那么订阅至顶网技术邮件将是您的最佳途径之一。

    重磅专题
    往期文章
    最新文章