当前位置:文档之家› 在WPF中创建可换肤的用户界面

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

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

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

周银辉译

原文参见: https://www.doczj.com/doc/f614562396.html,/WPF/SkinningInWPF.asp

介绍

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

背景

当”皮肤”这个术语被应用到用户界面中来时,就是指被运用于用户界面上的所有界面元素的可视化样式.一个可”换肤”的用户界面既可以是在编译时也可以是在运行时被定制(制定皮

肤).WPF为用户界面的”换肤”提供了强大的支持.

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

三大基础

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

层次型资源

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

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

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

合并的资源字典

ResourceDictionary类中有一个属性允许你从其它的ResourceDictionary实例来合并资源字典,这就像集合的”并集”.这个属性名叫MergedDictionaries,其类型为

Collection.下面这段话是SDK文档中用于解释资源合并时的域规则:在合并字典中的资源仅仅当它们被合并到主资源字典域中之后才在资源查找域中占有一个位置.尽管在独立的字典中其资源”键”必须是互不相同的,但在合并字典中一个”键”却可能出现

多次.因此,被返回的资源就来自于被合并的资源字典集合中的最后一个字典.如果这些被合并的

资源字典是用XAML定义的话,那么它们在合并字典中的顺序就于它们在XAML语言中被标记的顺序一致.如果一个”键”既包含于主字典又包含于其它被合并的字典,那么在主字典中的资源将

被返回.这些规则既适合动态资源引用也适合于静态资源引用.

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

动态资源引用

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

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

地用新画刷来更新Text Block对象的Background属性.

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

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

应用三大基础

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

资源了.

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

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

示例程序是什么样子的

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

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

作为一个实际的应用程序以这样的方式来允许用户选择皮肤似乎有一点奇怪了,但这仅仅是一个示例.如果用户在下拉列表中选择代理商的名称为”David”并且在上下文菜单中选择绿色,那么”绿色皮肤”将被应用,软件界面将如下图所示:

注意:选择最后一个代理商的名字与现在软件界面为绿色并没有任何联系.

我创建的最后一个皮肤有一点点怪异,但我喜欢,当应用”蓝色皮肤”时软件界面看

起来是这样的:

示例程序是如何运作的

下面是在Visual Studio的解决方案浏览器中我们的示例程序的项目结构:

允许用户更改皮肤的上下文菜单被定义在MainWindow的XAML文件中,如下所示:

当用户在菜单中选择一个新的”皮肤”时,在MainWindow的后台代码文件中以下代码将被执行:

void OnMenuItemClick(object sender, RoutedEventArgs e)

{

MenuItem item = e.OriginalSource as MenuItem;

// Update the checked state of the m enu item s.

Grid m ainGrid = this.Content as Grid;

foreach (MenuItem mi in mainGrid.ContextMenu.Item s)

mi.IsChecked = mi == item;

// Load the selected skin.

this.ApplySkinFromMenuItem(item);

}

void ApplySkinFromMenuItem(MenuItem item)

{

// Get a relative path to the ResourceDictionary which

// contains the selected skin.

string skinDictPath = item.Tag as string;

Uri skinDictUri =new Uri(skinDictPath, UriKind.Relative);

// Tell the Application to load the skin resources.

DemoApp app = Application.Current as DemoApp;

app.ApplySkin(skinDictUri);

}

DemoApp对象的ApplySkin方法的调用将导致下面的代码被执行:

public void ApplySkin(Uri skinDictionaryUri)

{

// Load the ResourceDictionary into m emory.

ResourceDictionary skinDict =

Application.LoadComponent(skinDictionaryUri) as ResourceDictionary;

Collection m ergedDicts =

base.Resources.MergedDictionaries;

// Remove the existing skin dictionary, if one exists.

// NOTE: In a real application, this logic might need

// to be more com plex, because there might be dictionaries

// which should not be rem oved.

if (m ergedDicts.Count > 0)

m ergedDicts.Clear();

// Apply the selected skin so that all elements in the

// application will honor the new look and feel.

m ergedDicts.Add(skinDict);

}

现在我们来看一个界面元素如何使用皮肤资源的例子,下面的XAML代码诚信了窗口左边的"Agents"区域,其包含了一个包含保险业代理商名字的下拉列表控件,其标题为"Agents".

x:Class="SkinnableApp.AgentSelectorControl"

xmlns="http://schem https://www.doczj.com/doc/f614562396.html,/winfx/2006/xaml/presentation"

xmlns:x="http://schem https://www.doczj.com/doc/f614562396.html,/winfx/2006/xaml"

>

Style="{Dynamic Resource styleContentArea}">

Style="{Dynamic Resource styleContentAreaHeader}"< /STRONG>>

Margin="4,4,0,4"

Source=".\Resources\Icons\agents.ico"

/>

FontSize="20"

Padding="8"

Text="Agents"

VerticalAlignment="Center"

/>

Background="T ransparent"

BorderThickness="0"

Grid.Row="1"

IsSynchronizedWithCurrentItem="T rue"

Item sSource="{Binding}"

Item Template="{Dynamic Resource agentListItem Tem plate}"

ScrollViewer.HorizontalScrollBarVisibility="Hidden"

/>

下图是AgentSelectorControl使用默认皮肤时的样子:

如上所示,在AgentSelectorControl中, Dynamic Resource扩展标记供使用了三处,它们每次引用的资源都必须存在于皮肤字典中.

外部链接

Resources Overview

Merged Resource Dictionaries

DynamicResource Markup Extension

How to set a property to a DynamicResource reference in code

ui用户界面设计课程设计报告

UI用户界面设计 大作业课程设计报告 题目:依依旅行系统前台应用及后台管理院别:信息与控制学院 专业:计算机科学与技术 学生姓名: 7宋依依 指导教师:孙丽云 成绩: 2015年 6 月 12 日 一、系统概述 1.1课程设计题目: 依依旅行系统前台及后台管理 1.2 课程设计运行环境: Java,MyEclipse6.5,Tomcat5.x Microsoft SQL Server 2008 360安全浏览器7.1 1.3 课程设计实现技术: 基于HTML,CSS,JSP等技术的应用 二、依依旅行系统需求分析 2.1系统功能需求:

系统的功能需求包括一下几个方面 (1)游客在不登录的情况下只可以进行相关旅行,车票,酒店信息的查询。(2)游客通过注册登录或者登录后,可以通过网络查询景点的信息概况和预定景点票,酒店,车票(飞机票,火车票,或者租车)。 (3)游客登录后还可以进行各种订单的退订,个人信息的修改。 (4)系统管理员可以查看游客的预定请求和取消预定的请求。 (5)系统管理员可以对系统的数据库进行维护,例如增加、删除和修改景点信息,增加、删除工作人员帐户,增加和删除旅行用户。 三、依依旅行系统概要分析 3.1旅游系统模块介绍 满足以上需求的管理系统主要包括以下几个模块。 (1)旅游数据维护模块 基本数据维护模块提供了使用者录入、修改并维护基本数据的途径。例如对游客及导游及工作人员各项信息的更新和修改。 (2)旅游业务模块 基本业务模块主要用于实现游客查询景点信息和预定的管理,可以登陆系统预定景点游票和导游预定,工作人员可以处理预定信息和取消预定信息等操作。 (3)数据库管理模块 在系统中,所有景点信息以及工作人员和导游的帐户信息都要进行统一管理,景点的使用情况和预定情况也要进行详细的记录,要用统一的数据库平台进行管理。 (4)旅游信息查询模块 信息查询模块主要用于查询景点的信息和游客的预定信息。 下图所示表示了旅游开发管理系统的功能需求: 3.2旅游数据维护模块 数据维护模块包括如下图所示的几个方面: (1)修改更新景点信息:系统管理员可以更新和修改景点信息。 (2)更新和修改信息:系统管理员可以更新和修改旅游景点和酒店出行,删除游客的信息。 (3)添加景点信息:系统管理员可以添加景点及景点信息。 (4)删除景点信息:系统管理员可以删除景点及景点信息。 3.3旅游业务模块 旅游业务模块包括一下几个方面: (1)注册登陆后,更改个人信息 (2)查询信息:游客查询景点使用信息及景点概括信息。 (3)预定取消景点:游客预定景点票。 (4)酒店预订:游客可一根据情况预定酒店。 (5)出行方式:游客可以根据自己的情况选择出行方式。 3.4数据库管理模块 数据库模块包括一下一个方面: (1)游客信息管理:信息包括游客的姓名,电话号码,及联系方式等。(2)景点信息管理:景点信息包括景点的名称,代号,概况等。

wpf自定义slider控件

自定义Slider控件 最终效果: 界面: