转载自 胡庆访http://zgynhqf.cnblogs.com/ ]

WPF 是一个界面层框架技术,要对 WPF 技术达到熟练运用的程度,需要同时拥有开发和设计两方面的知识。而我作为一名开发人员,以前的总结都是站在开发人员的角度,今天这篇博文则期望更多地站在设计人员的角度来进行总结。其实,开发人员比较难理解WPF 框架中为什么会提出 Style、Template、Command、State、StoryBoard、Trigger 等这些概念,但是当你看一看 Flash 或者 PhotoShop 的设计人员平时的工作,就会发现原来许多概念早已是他们的常识,而 .NET 只是把这些概念在 WPF 框架上加以实现而已。

最近接了一个 WPF 的活,对方要求我按照他们美工所画的图,使用 WPF 技术构建一模一样的用户界面。目前项目已经结束,也收到了约定的劳务费用。由于做得还不错,所以他们又和我约定了两个更复杂的项目。其实我个人的 WPF 技术并不高,所以接这个活的一部分原因还是期望通过设计实际的 WPF 项目,来锻炼自己的 WPF 技术。而本篇博文和之前的 WPF 总结不同,主要是想简洁地总结一下项目中的 WPF 实战经验。也就是说,一是只涉及这个项目中用到的概念,而不是所有 WPF 中的概念;二是不会把某个概念技术说透,只从设计人员的角度去讲使用方法。

Template


模板是一个可视化控件结构定义,也就是最终界面显示的可视树中控件结构。主要分为两个,一个是 DataTemplate,一个是 ControlTemplate。

DataTemplate 用于为某一类数据定义可视化控件结构。而 ControlTemplate 则是为某一种类型的逻辑控件定义可视化控件结构。一般情况下,使用 ControlTemplate 的场景要远远多过 DataTemplate。

那么如何设计一个 ControlTemplate 中的控件结构呢?其实分两步,第一步,设计这个控件的静态结构;第二步,设计控件的动态行为。其实都很简单,使用 Microsoft Expression Blend 这个专业的 WPF/Silverlight 设计工具进行界面设计,拖拖拽拽就搞定了。

这里要注意的是可视树中的动态行为。主要有两种,一种是模板内部根据各可视控件状态变化而变化的属性设置,可以直接编写在 ControlTemplate 的 Triggers 中,Blend 中则可以直接在 Trigger 面板中进行设计;而另一种行为则需要通过与外层逻辑控件的交互完成。交互的方式有:直接绑定逻辑控件属性、路由命令、路由事件、PART_设计约定。

后三种方式是必须要编写代码才能完成的行为。虽然它们并不是设计人员的工作,但是它们是连接开发与设计的桥梁,鉴于它们的重要性,这里还是专门说明一下:

  1. 路由事件
    在设计自定义逻辑控件时,可以在类型的静态构造器中使用 EventManager.RegisterClassHandler 来处理内部可视树中所有元素的路由事件。举个简单的例子:在 Button 类型的设计代码中,为 LeftMouseButtonDown 事件注册了处理函数,并转换为自己的 Click 事件,这样,点击 Button 内部所有可视控件时,才会触发 Button 的 Click 事件。
    这是一种逻辑控件主动去处理或转换可视控件行为的方式。
  2. 路由命令
    我认为这是一种可视控件主动挑选命令,而逻辑控件被动执行命令调用的方式。
    机制是这样的:控件开发人员为逻辑控件设计了相应的一些行为,但是他们并不知道设计人员会在可视树中用哪一个具体的元素来执行这个行为。这时,开发人员为逻辑控件编写一个路由命令,并在类型静态构造器中为该命令注册处理函数执行相应的控件逻辑。设计人员则只需要在设计控件模板时,为具体元素设置 Command 即可。这样,由于命令也是通过路由事件来进行路由的,所以内部的可视树控件执行命令时,会一直路由到上层的逻辑控件上,并被相应的逻辑处理。达到可视树控件与逻辑控件交互的效果。
  3. PART_ 逻辑控件设计约定
    当开发一个自定义控件时,如果知道这个控件对应的模板中,必须要有一个某一类型控件,这时我们就可以要求模板设计人员必须在模板中添加该类型的控件,并以一个固定的名称命名。这样,开发人员就能在逻辑控件的 ApplyTemplate 方法中通过 Template.Find 找到对应的控件,然后就可以对它进行事件监听、属性控制等操作。而连接逻辑控件、模板中可视树控件的那个名字,为了和一般的命名区分开并显示其重要性,需要使用“PART_” 起头。
    例如,ComboBox 就在类型设计时,指定了至少需要以下两个控件,才能发生正常的下拉行为:

Style


样式本质上是对控件的一组属性设置集合。

当我们设计好一个 Style 后,可以把它应用到对应控件的许多实例上,那么就算是通过 Style 默认设置好了这些属性。另外,Style 还提供了 Trigger,可以实现简单地属性变更时设置其它属性的功能。一般较少使用到 EventTrigger。

Style 中我们常常看到的最长的一个属性设置就是设置 Template 属性,即控件的模板。虽然他们俩往往出现在一起,但是 Style 跟 Template 其实没有直接的关系,Style 所做的只是简单地设置一下控件的 Template 属性值而已。

有些朋友会问:要达到同样一个效果,我们也可以在 Template 中直接设置视觉控件的属性,例如直接设置边框宽度。那么,为什么还要把一些属性设置编写在 Style 中,再去让 Template 中的控件进行模板绑定,这不是太绕了吗?其实,这样做的好处是使得模板中视觉控件的属性值不会被写成固定值,可以随着外层逻辑控件属性值的变化而变化。这样,当我们直接给逻辑控件设置边框宽度时(本地值),模板中的可视控件就会使用这个更高优先级的值来显示边框。

自定义控件


在开发实际项目时,一般都会遇到要开发自定义控件的情况。相关内容上面已经都谈到了,其实挺简单的:

  1. 想好逻辑控件要提供的功能。
  2. 思考这些功能需要为模板设计人员提供哪些接口,一般是:依赖属性、路由命令、PART_ 控件约定。(参考上面的 Template 设计。)
  3. 交互机制确定后,就可以编写相应的后台逻辑控制代码 以及 默认的控件样式(含模板)。

其它 Tips 及小技巧


  1. Blend 设计界面固然快,但是每次都需要编译、运行,要看一个效果往往需要多次调整。这时,我们可以使用 snoop 工具来直接调整运行时软件,当效果达到要求时,再把这些满意的值调整到 Blend 中。
  2. 一定要使用 Blend 而不是 VS 来设计界面,除非你对界面没有一点要求。
  3. 忘记“我用 VS 也能设计 WPF 界面”这种不切实际的想法吧。我个人就是因为之前有这种想法,导致一直对 WPF 不开窍。我认为这是一个学习 WPF 的误区,老是以开发人员的思维去思考 WPF。
  4. 学习 Blend 其实是很简单的一件事,相比 VS 的学习成本就简单太多了。如果你要是玩过 Flash、PS,玩起 Blend 来会更快。
  5. 虽然 Blend 说是给设计人员用的,但是我认为只有开发人员才能真正地用好 Blend,用好 WPF。
  6. 对于 XAML,不要象 C# 代码一样的追求代码重用。这种东西,Copy 一下改改就可以了。
  7. Theme 和 Resource:Theme 是主题文件,随着操作系统的主题变化。在开发自定义控件时会自动生成一个 Theme/Generic.xaml 文件。 可以在 Theme/ 这个文件夹中为不同的操作系统主题设计不同的控件样式,而找不到相关主题对应的文件时,则会使用 Generic.xaml 文件中的控件样式。所以:除了自定义控件的样式需要放到 Theme 中,当某个资源要随着系统主题变化而变化时,也需要把它编写到 Theme 文件夹中,否则,应该放到单独的资源文件中并收入到 Application 中。(这一点是个人的理解,不知道对不对,希望懂的大牛给指点下。)

转载 wpf使用经验的更多相关文章

  1. 转载 WPF -- 控件模板 (ControlTemplate)(一) https://blog.csdn.net/qq_23018459/article/details/79899838

    ControlTemplate(控件模板)   https://blog.csdn.net/qq_23018459/article/details/79899838 WPF包含数据模板和控件模板,其中 ...

  2. 转载WPF SDK研究 之 AppModel

    Jianqiang's Mobile Dev Blog iOS.Android.WP CnBlogs Home New Post Contact Admin Rss Posts - 528 Artic ...

  3. [转载]WPF控件拖动

    这篇博文总结下WPF中的拖动,文章内容主要包括: 1.拖动窗口 2.拖动控件 Using Visual Studio 2.1thumb控件 2.2Drag.Drop(不连续,没有中间动画) 2.3拖动 ...

  4. 转载WPF:创建你的第一个WPF项目

    转载:http://www.cnblogs.com/pengjinyu/archive/2009/08/19/1549845.html

  5. (转载)WPF:DataGrid设置行、单元格的前景色

    WPF:DataGrid设置行.单元格的前景色 0. 说明 /********************************** 本示例实现功能1.DataGrid基本操作2.列标题样式3.内容居中 ...

  6. (转载)解决WPF动画属性锁死问题

    此文来自: 马开东博客 转载请注明出处 网址:http://www.makaidong.com 一般锁死问题都是出在后台代码写的动画中,以下为转载的解决方案! 方法一:将动画的 FillBehavio ...

  7. WPF之Binding深入探讨 转载:http://blog.csdn.net/fwj380891124/article/details/8107646

    1,Data Binding在WPF中的地位 程序的本质是数据+算法.数据会在存储.逻辑和界面三层之间流通,所以站在数据的角度上来看,这三层都很重要.但算法在3层中的分布是不均匀的,对于一个3层结构的 ...

  8. 潜移默化学会WPF(转载篇)--屏幕显示Label,鼠标移上去变成textBox

    原文:潜移默化学会WPF(转载篇)--屏幕显示Label,鼠标移上去变成textBox <Window x:Class="WpfApplication1.Window1" x ...

  9. 【转载】 wpf无边框的方法以及拖拽的问题

    今天在做wpf程序的时候遇到了一个制作无边框的窗体并且有透明圆角的问题,我把解决的过程写下来,和大家学习 正常窗体必须把WindowStyle="None"这个属性加上去,但是加上 ...

随机推荐

  1. poj2104 K-th Number区间第k小值 主席树

    原来主席树就是可持久化线段树啊,刚知道,,, 作为一道裸题,还是必A的,然而一开始偷懒不写离散化跪了N多遍,后来在缪大的帮助下发现了这个问题,遂A之 ——又是这种破问题,实在不想说自己了 把n个数看成 ...

  2. 【BZOJ】3930: [CQOI2015]选数

    题意 从区间\([L, R]\)选\(N\)个数(可以重复),问这\(N\)个数的最大公约数是\(K\)的方案数.(\(1 \le N, K \le 10^9, 1 \le L \le R \le 1 ...

  3. *HDU3357 判环

    Stock Chase Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total ...

  4. bzoj4511:[Usaco2016 Jan]Subsequences Summing to Sevens

    题目大意:给个序列,求最长的连续子序列使其为7的倍数 又是一道令人欢喜的不用怎么用脑的水题.. 边读入,边计算前缀和 分别保存前缀和%7结果为1,2,3,4,5,6的第一次的位置 然后减一减就知道长度 ...

  5. AADC安装指南

    可选功能中,”密码哈希同步“可以将本地域账号的密码默认每三小时同步到O365:”密码回写“则是反过来,但是世纪互联的答复是”此功能需要Auzre AD Service功能,目前国内版还不支持使用,国际 ...

  6. 10 款最好的 Python IDE

    Python 非常易学,强大的编程语言.Python 包括高效高级的数据结构,提供简单且高效的面向对象编程. Python 的学习过程少不了 IDE 或者代码编辑器,或者集成的开发编辑器(IDE).这 ...

  7. rabbitmq使用心得

    因为公司项目需要使用消息中间件,实现相关业务的异步处理,所有选用了rabbitmq.通过看文档,爬过一个一个坑,终于还是实现了相关功能. 直接上配置文件: <?xml version=" ...

  8. 阿里云服务器Linux CentOS安装配置(三)yum安装mysql

    阿里云服务器Linux CentOS安装配置(三)yum安装mysql 1.执行yum安装mysql命令:yum -y install mysql-server mysql-devel 2.启动mys ...

  9. 展望 2017年商业智能BI 发展的趋势

    在展望2017年商业智能 BI 发展趋势前,我们先来了解一下商业智能 BI 发展的几个重要阶段. 传统 BI 和新型 BI 的分水岭(2013年) 大背景 在2013年以前相当长的一个周期(2005年 ...

  10. maven settings.xml 阿里云

    <?xml version="1.0" encoding="UTF-8"?> <!--Licensed to the Apache Softw ...