转载自 胡庆访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. hg 的使用简介

    克隆仓库 仓库是一个目录,它包含所有我们希望保留历史的源代码和这些源代码的历史记录. 克隆就是生产一个仓库的副本,这样可以有一个本地私有的仓库来工作. hg clone http://远程仓库地址:端 ...

  2. Easyui的Dialog的toolbar的自定义添加

    最近一直在写快速定制Web表格,基于Easyui,整个过程使用了大量的Easyui的dialog,每个dialog的代码大部分都雷同,感觉代码出现了很大程度的重复,然后想写一个通用的dialog设置函 ...

  3. WIN7 如何将BAT文件附加到任务栏

    1.桌面有个 a.bat 文件2.将a.bat 改名为 a.exe3.将 a.exe 拉到任务栏4.修改桌面的 a.exe 回 a.bat5.打开C:\Users\Administrator\AppD ...

  4. 《UML大战需求分析》阅读笔记06

    对<UML>撒站需求分析的阅读现在已到达尾声,虽然读这本书是应老师的要求,但是在后期的阅读中也逐渐喜欢上这本书,在阅读的过程中不断领会需求分析与UML之间的联系,让在软件需求分析阶段有了更 ...

  5. linux建立文件夹软连接

    linux建立文件夹软连接,并强制覆盖 ln -sfn /home/var/log/httpd/logs logs 这将在当前目录下建立logs软连接,指向/home/var/log/httpd/lo ...

  6. 从程序员到CTO的Java技术路线图(我爱分享)

    在技术方面无论我们怎么学习,总感觉需要提升自已不知道自己处于什么水平了.但如果有清晰的指示图供参考还是非常不错的,这样我们清楚的知道我们大概处于那个阶段和水平. Java程序员 高级特性 反射.泛型. ...

  7. Linux学习笔记

    性能问题排查: Linux系统出现了性能问题,一般我们可以通过top.iostat.free.vmstat等命令来查看初步定位问题.内存资源占用:free命令 IO占用:iostat -d -k 1 ...

  8. hive --service metastore 出现的问题

    Could not create ServerSocket on address 0.0.0.0/0.0.0.0:9083 执行命令jps root@hadoopm:/usr# jps1763 Res ...

  9. golang DynamoDB sdk AccessDeniedException

    golang调用aws sdk时候提示: AccessDeniedException: User: arn:aws:sts::818539432014:assumed-role/bj-develop/ ...

  10. 在Update表数据同时将数据备份

    分享一条有意思的SQL语句,也是前两天有个朋友在面试的时候碰到的,他当时没有做出来,回来之后问我, 如何在同一条语句中实现,更新表的时候同时备份更新前的记录数据. --在修改数据前,先要把修改前的数据 ...