<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom"><title type="text">博客园_技术改变生活</title><subtitle type="text">安于现状，止于现状</subtitle><id>http://feed.cnblogs.com/blog/u/28104/rss</id><updated>2012-04-18T06:06:54Z</updated><author><name>周永恒</name><uri>http://www.cnblogs.com/Zhouyongh/</uri></author><generator>feed.cnblogs.com</generator><link rel="alternate" type="text/html" href="http://www.cnblogs.com/Zhouyongh/"/><link rel="self" type="application/atom+xml" href="http://feed.cnblogs.com/blog/u/28104/rss"/><entry><id>http://www.cnblogs.com/Zhouyongh/archive/2012/02/16/2353498.html</id><title type="text">WPF插件式框架</title><summary type="text">本文主要介绍了WPF插件式框架的一个思路，代码来自于以前给朋友写的一个Sample，希望能给朋友们带来些帮助。</summary><published>2012-02-16T06:27:00Z</published><updated>2012-02-16T06:27:00Z</updated><author><name>周永恒</name><uri>http://www.cnblogs.com/Zhouyongh/</uri></author><link rel="alternate" href="http://www.cnblogs.com/Zhouyongh/archive/2012/02/16/2353498.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/Zhouyongh/archive/2012/02/16/2353498.html"/><content type="html">&lt;h1 style="padding-bottom: 5px; background-color: gray; margin-top: 24px; padding-left: 5px; padding-right: 5px; margin-bottom: 12px; color: white; font-size: 26px; font-weight: normal; padding-top: 5px"&gt;前言&lt;/strong&gt;&lt;/p&gt; &lt;p&gt;标题有点大，本文主要介绍了WPF插件式框架的一个思路，代码来自于以前给朋友写的一个Sample，细节地方不去关注，大致谈谈想法。&lt;/p&gt; &lt;h1 style="padding-bottom: 5px; background-color: gray; margin-top: 24px; padding-left: 5px; padding-right: 5px; margin-bottom: 12px; color: white; font-size: 26px; font-weight: normal; padding-top: 5px"&gt;插件式架构&lt;/strong&gt;&lt;/p&gt; &lt;p&gt;插件式（AddIn）架构，不是一个新名词，应用程序采用插件式拼合，可以更好的支持扩展。很多著名的软件都采用了插件式的架构，如常见的IDE：EClipse，VisualStudio等等。&lt;/p&gt; &lt;p&gt;这些插件式架构在实现上各有特色，但是基本原理大致相同：&lt;/p&gt; &lt;ol&gt; &lt;li&gt;定义插件框架，用来下载，创建，销毁插件，并管理插件间的通信等等。  &lt;/li&gt;&lt;li&gt;定义插件契约，定义统一的接口规范。  &lt;/li&gt;&lt;li&gt;实现插件组件，组件实现插件契约，在运行时可以被插件框架所发现并集成。&lt;/li&gt;&lt;/ol&gt; &lt;p&gt;关于插件式架构的实现技术，可以有很多选择，使用动态链接库的导出函数，使用COM技术等等，这里选择的是.net的MEF，MEF（Managed Extensibility Framework）是微软集成在.net framework中的扩展性管理框架，VisualStudio2010就是使用了MEF来管理插件，关于MEF的具体使用，请参见MSDN，这里不详细介绍了。&lt;/p&gt; &lt;h1 style="padding-bottom: 5px; background-color: gray; margin-top: 24px; padding-left: 5px; padding-right: 5px; margin-bottom: 12px; color: white; font-size: 26px; font-weight: normal; padding-top: 5px"&gt;设计与实现&lt;/strong&gt;&lt;/p&gt; &lt;p&gt;工程目录以及架构图如下所示：&lt;/p&gt; &lt;p&gt;&lt;a href="http://images.cnblogs.com/cnblogs_com/Zhouyongh/201202/20120216013013590.png"&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: left; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="1" border="0" alt="1" align="left" src="http://images.cnblogs.com/cnblogs_com/Zhouyongh/201202/201202160130142783.png" width="239" height="405" /&gt;&lt;/a&gt;&lt;a href="http://images.cnblogs.com/cnblogs_com/Zhouyongh/201202/201202160130147309.png"&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://images.cnblogs.com/cnblogs_com/Zhouyongh/201202/201202160130154376.png" width="956" height="608" /&gt;&lt;/a&gt;&lt;/p&gt; &lt;p&gt;Illusion中使用MEF实现了插件管理，通用的Services等等，Illusion作为一个Core模块，可以参见&lt;a href="http://www.cnblogs.com/Zhouyongh/archive/2011/07/18/2109345.html#2309439"&gt;前文&lt;/a&gt;。&lt;/p&gt; &lt;p&gt;Workbench定义了插件的工作台，定义了UI的布局。&lt;/p&gt; &lt;p&gt;Presentation定义了UI的具体实现，可以添加/替换UI的表现，默认提供了Ribbon和Default两种形式，可以点击选项-显示框架来动态切换整个UI。&lt;/p&gt; &lt;h1 style="padding-bottom: 5px; background-color: gray; margin-top: 24px; padding-left: 5px; padding-right: 5px; margin-bottom: 12px; color: white; font-size: 26px; font-weight: normal; padding-top: 5px"&gt;总结&lt;/strong&gt;&lt;/p&gt; &lt;p&gt;插件式架构应用程序不是什么新奇的东西，把UI布局和UI表现分离，并支持插件式架构是设计时的一些想法，具体到项目应用还需要一定的完善。代码放置很久了，拿出来分享一下，希望对朋友们有所帮助。&lt;/p&gt; &lt;p&gt;项目代码可以点击&lt;a href="http://files.cnblogs.com/Zhouyongh/YoZuo.rar"&gt;这里&lt;/a&gt;下载。&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;div&gt;&lt;span style="line-height: 25px; color: #333333"&gt;&lt;span style="line-height: 25px; background-color: #ffffff; font-family: georgia; color: #333333"&gt;&lt;span style="padding-bottom: 0px; line-height: 21px; margin: 0px; padding-left: 0px; padding-right: 0px; font-family: 宋体; color: black; font-size: 9pt; padding-top: 0px"&gt;作者：&lt;/span&gt;&lt;span style="padding-bottom: 0px; line-height: 21px; margin: 0px; padding-left: 0px; padding-right: 0px; font-family: verdana, sans-serif; color: black; font-size: 9pt; padding-top: 0px"&gt;&lt;a style="border-bottom: 1px dashed; padding-bottom: 0px; margin: 0px; outline-style: none; outline-color: ; padding-left: 0px; padding-right: 0px; color: #3d81ee; text-decoration: none; padding-top: 0px" href="http://www.cnblogs.com/Zhouyongh" target="_blank"&gt;&lt;span style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; font-family: 宋体; color: #ff6600; text-decoration: none; padding-top: 0px"&gt;周永恒&lt;/span&gt;&lt;/a&gt; &lt;br style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px" /&gt;&lt;/span&gt;&lt;span style="padding-bottom: 0px; line-height: 21px; margin: 0px; padding-left: 0px; padding-right: 0px; font-family: 宋体; color: black; font-size: 9pt; padding-top: 0px"&gt;出处：&lt;/span&gt;&lt;span style="padding-bottom: 0px; line-height: 21px; margin: 0px; padding-left: 0px; padding-right: 0px; font-family: verdana, sans-serif; color: black; font-size: 9pt; padding-top: 0px"&gt;&lt;a style="border-bottom: 1px dashed; padding-bottom: 0px; margin: 0px; outline-style: none; outline-color: ; padding-left: 0px; padding-right: 0px; color: #3d81ee; text-decoration: none; padding-top: 0px" href="http://www.cnblogs.com/Zhouyongh" target="_blank"&gt;&lt;span style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; color: #ff6600; text-decoration: none; padding-top: 0px"&gt;http://www.cnblogs.com/Zhouyongh&lt;/span&gt;&lt;/a&gt; &lt;br style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px" /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt; &lt;p&gt;&lt;span style="line-height: 25px; font-family: 宋体; color: #333333; font-size: 12px" class="Apple-style-span"&gt;本文版权归作者和博客园共有，欢迎转载，但未经作者同意必须保留此段声明，且在文章页面明显位置给出原文连接，否则保留追究法律责任的权利。&lt;/span&gt;&lt;/p&gt;&lt;img src="http://www.cnblogs.com/Zhouyongh/aggbug/2353498.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/Zhouyongh/archive/2012/02/16/2353498.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/Zhouyongh/archive/2012/02/16/2212217.html</id><title type="text">面向对象（OO）程序设计</title><summary type="text">本文主要介绍了面向对象（OO）程序设计，谈设计难免有经验和偏向，希望能给朋友们带来些帮助。</summary><published>2012-02-16T03:04:00Z</published><updated>2012-02-16T03:04:00Z</updated><author><name>周永恒</name><uri>http://www.cnblogs.com/Zhouyongh/</uri></author><link rel="alternate" href="http://www.cnblogs.com/Zhouyongh/archive/2012/02/16/2212217.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/Zhouyongh/archive/2012/02/16/2212217.html"/><content type="html">&lt;h1 style="padding-bottom: 5px; background-color: gray; margin-top: 24px; padding-left: 5px; padding-right: 5px; margin-bottom: 12px; color: white; font-size: 26px; font-weight: normal; padding-top: 5px"&gt;前言&lt;/strong&gt;&lt;/p&gt; &lt;p&gt;本文主要介绍面向对象（OO）程序设计，以维基百科的解释：&lt;/p&gt; &lt;blockquote style='border:2px solid #EFEFEF;color:#333333;padding:5px 10px;'&gt; &lt;p&gt;&lt;strong&gt;面向对象程序设计&lt;/strong&gt;（&lt;a href="http://zh.wikipedia.org/wiki/%E8%8B%B1%E8%AF%AD"&gt;英语&lt;/a&gt;：&lt;strong&gt;Object-oriented programming&lt;/strong&gt;，缩写：&lt;strong&gt;OOP&lt;/strong&gt;），指一种&lt;a href="http://zh.wikipedia.org/wiki/%E7%A8%8B%E5%BA%8F%E8%AE%BE%E8%AE%A1%E8%8C%83%E5%9E%8B"&gt;程序设计范型&lt;/a&gt;，同时也是一种程序开发的方法。它将&lt;a href="http://zh.wikipedia.org/wiki/%E7%89%A9%E4%BB%B6_(%E9%9B%BB%E8%85%A6%E7%A7%91%E5%AD%B8)"&gt;对象&lt;/a&gt;作为&lt;a href="http://zh.wikipedia.org/wiki/%E7%A8%8B%E5%BA%8F"&gt;程序&lt;/a&gt;的基本单元，将程序和&lt;a href="http://zh.wikipedia.org/wiki/%E6%95%B0%E6%8D%AE"&gt;数据&lt;/a&gt;&lt;a href="http://zh.wikipedia.org/wiki/%E5%B0%81%E8%A3%9D_(%E7%89%A9%E4%BB%B6%E5%B0%8E%E5%90%91%E7%A8%8B%E5%BC%8F%E8%A8%AD%E8%A8%88)"&gt;封装&lt;/a&gt;其中，以提高软件的重用性、灵活性和扩展性。&lt;/p&gt;&lt;/blockquote&gt; &lt;p&gt;简略来说，面向对象程序设计，指采用了面向对象的方法来进行程序设计。设计指一种把计划、规划、设想通过视觉传达出来的活动过程，它是一种创造性，积累性，实践性的工作。提笔写设计的文章是很有压力的，它不像深入一个知识点一样让人容易有的放矢，一千个读者心中有一千个哈姆雷特，同样的项目两个人来做架构肯定不一样。包括我，每几年对设计都会有一些不同的看法，回头来看自己的代码也总会挑出很多不足，世界是不完美的，设计却希望尽求完美，闲话不说，来进入本文的正题，看看从何谈起。&lt;/p&gt; &lt;h1 style="padding-bottom: 5px; background-color: gray; margin-top: 24px; padding-left: 5px; padding-right: 5px; margin-bottom: 12px; color: white; font-size: 26px; font-weight: normal; padding-top: 5px"&gt;面向过程程序设计&lt;/strong&gt;&lt;/p&gt; &lt;p&gt;面向过程程序设计不是面向对象程序设计的前提，从面向过程谈起主要是因为自面向对象（OO）程序设计一提出，就有太多的两者对比。在这样的对比中，面向过程被形容成老化，腐朽，僵硬的设计模式，它自上而下，按照功能逐渐细化，实现快速但面对变化时束手无策。相对而言面向对象具有封装性，重用性，扩展性等一系列优点，言而总之：&amp;#8220;还面向过程？？你out了，来面向对象吧。。。&amp;#8221;&lt;/p&gt; &lt;p&gt;C语言是面向过程的代表，它在1972年由贝尔实验室的D.M.Ritchie提出，在Unix系统中大放异彩，直至今天在系统软件，图形动画，嵌入开发等众多领域中还保持着旺盛的生命力。程序设计这个概念，伴随着程序开发被提出，最简略的被描述为 &lt;strong&gt;程序设计&lt;/strong&gt;=&lt;strong&gt;数据结构&lt;/strong&gt;+&lt;strong&gt;算法&lt;/strong&gt;，通俗一点的说程序设计指的是设计、编制、调试程序的方法和过程。人是善于思考总结的，在漫长的面向过程的程序开发中，一些设计原则被提出，用以更好的指导设计：&lt;/p&gt; &lt;ol&gt; &lt;li&gt;模块原则：使用简单的接口拼合简单的部件。  &lt;/li&gt;&lt;li&gt;清晰原则：清晰胜于技巧。  &lt;/li&gt;&lt;li&gt;组合原则：设计时考虑拼接组合。  &lt;/li&gt;&lt;li&gt;分离原则：策略同机制分离，接口同引擎分离。  &lt;/li&gt;&lt;li&gt;简洁原则：设计要简洁，复杂度能低则低。  &lt;/li&gt;&lt;li&gt;透明性原则：设计要可见，以便审查和调试。  &lt;/li&gt;&lt;li&gt;健壮原则：健壮源于透明和简洁。  &lt;/li&gt;&lt;li&gt;优化原则：雕琢之前先要有原型，跑之前先学会走，不要过早优化。  &lt;/li&gt;&lt;li&gt;扩展原则：设计着眼于未来，未来总比预想快。&lt;/li&gt;&lt;/ol&gt; &lt;p&gt;以上原则参考自《Unix编程艺术》，书中总结了17种原则来指导程序设计，精简为一句话就是Unix哲学&amp;#8220;KISS&amp;#8212;Keep It Simple, Stupid!&amp;#8221;，保持简单。&lt;/p&gt; &lt;p&gt;KISS，Keep Simple，Keep是它的核心词，底层的API设计，可以尽量保持简洁清晰，外部的需求变化，Keep？你Hold得住么？&lt;/p&gt; &lt;h1 style="padding-bottom: 5px; background-color: gray; margin-top: 24px; padding-left: 5px; padding-right: 5px; margin-bottom: 12px; color: white; font-size: 26px; font-weight: normal; padding-top: 5px"&gt;需求变化，你Hold得住么？&lt;/strong&gt;&lt;/p&gt; &lt;p&gt;你Hold不住！&lt;/p&gt; &lt;p&gt;变化来源于对事物认识的发展和外部业务的变更，当然实际中变化可能来自于更多方面。你不能拒绝变化，你只能拥抱变化，在长期的程序设计中，两条设计原则被提出：&lt;/p&gt; &lt;ol&gt; &lt;li&gt;简洁，用更长的三个词来说应该是简洁，清晰，透明。程序应该易于读懂，易于维护，最好有文档注释。世界在变，规则在变，今天精巧的设计，可能成为明天修改的沉重包袱。  &lt;/li&gt;&lt;li&gt;重构，在不改变软件现有的功能上，通过调整程序代码而改善软件质量，性能等。面向过程中重构的原则性目标在于提高正交性，所谓正交性，是指任何操作均无副作用，每一个动作只改变一件事，不会影响其它。具体到API设计就是一个API中不应做两件事，一个粗粒度内部做几种事情的接口可以细化为多个细粒度的接口，&amp;#8220;只做好一件事&amp;#8221;，这个忠告不仅是针对简单性的建议，对正交性也是同等程度的强调。&lt;/li&gt;&lt;/ol&gt; &lt;p&gt;按照正交性的设想，我们应该打造一个纯正交的系统，在这个设计中，任何操作均无副作用，每一个动作只改变一件事不会影响其它，改变一件事情一个具体方面的方法只有一个。想法是完美的，世界是复杂的，软件要能做到拥抱变化，设计希望达到高内聚（模块内元素紧密结合），低耦合（模块间依赖尽可能低），那么如何来拥抱变化呢？&lt;/p&gt; &lt;h1 style="padding-bottom: 5px; background-color: gray; margin-top: 24px; padding-left: 5px; padding-right: 5px; margin-bottom: 12px; color: white; font-size: 26px; font-weight: normal; padding-top: 5px"&gt;让它&amp;#8220;活&amp;#8221;起来&lt;/strong&gt;&lt;/p&gt; &lt;p&gt;程序最有魅力的事情在于创造，程序员使用代码来完成程序的创造。一花一世界，一木一浮生，作为粘土世界的上帝，我们采取了很多的努力来完成我们的设计：&lt;/p&gt; &lt;ol&gt; &lt;li&gt;分清程序中可变和不可变的部分，相对来说，数据是不可变的，算法是可变的，我们设计好相对稳定的数据，再细化算法，应对变更。  &lt;/li&gt;&lt;li&gt;以模块化来划分程序，按功能来划分模块，这样从纵向看，程序是由一个个的模块组成的，从横向看，我们定义好模块间通信的接口，程序就是由模块组织起来的联合体。&lt;/li&gt;&lt;/ol&gt; &lt;p&gt;程序像流水线一样工作起来了，数据从上到下开始运作，但是变化仍然无处不在，大修小补依然无法避免。如果模块设计的足够独立，程序的正交性足够好，变动还在可控范围之内。一旦变化跨越多个模块，程序经过多次大修，就会有种想把它捏回泥巴的冲动。&lt;/p&gt; &lt;p&gt;外部的变化还在继续，里面依旧是勤恳，冰冷的泥块，怎么来拥抱变化？对，伸出你的金手指，让它&amp;#8220;活&amp;#8221;起来。&lt;/p&gt; &lt;h1 style="padding-bottom: 5px; background-color: gray; margin-top: 24px; padding-left: 5px; padding-right: 5px; margin-bottom: 12px; color: white; font-size: 26px; font-weight: normal; padding-top: 5px"&gt;对象&lt;/strong&gt;&lt;/p&gt; &lt;p&gt;英雄应运而生，对象应责而生。我们点&amp;#8220;活&amp;#8221;了对象，就是为了让它解决事情承担责任。从：&lt;/p&gt; &lt;div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 100%; padding-right: 4px; font-family: 'Courier New', courier, monospace; direction: ltr; font-size: 8pt; overflow: hidden; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"&gt; &lt;div style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: hidden; padding-top: 0px" id="codeSnippet"&gt;&lt;span style="color: #606060" id="lnum1"&gt;   1:&lt;/span&gt; &lt;span style="color: #0000ff"&gt;struct&lt;/span&gt; Data&lt;!--CRLF--&gt;&lt;span style="color: #606060" id="lnum2"&gt;   2:&lt;/span&gt; {&lt;!--CRLF--&gt;&lt;span style="color: #606060" id="lnum3"&gt;   3:&lt;/span&gt;     &lt;span style="color: #0000ff"&gt;int&lt;/span&gt; d;&lt;!--CRLF--&gt;&lt;span style="color: #606060" id="lnum4"&gt;   4:&lt;/span&gt; };&lt;!--CRLF--&gt;&lt;span style="color: #606060" id="lnum5"&gt;   5:&lt;/span&gt; &lt;span style="color: #0000ff"&gt;void&lt;/span&gt; increase_data(Data* data)&lt;!--CRLF--&gt;&lt;span style="color: #606060" id="lnum6"&gt;   6:&lt;/span&gt; {&lt;!--CRLF--&gt;&lt;span style="color: #606060" id="lnum7"&gt;   7:&lt;/span&gt;     printf(&lt;span style="color: #006080"&gt;"过程调用，数据为： %d"&lt;/span&gt;, ++data-&amp;gt;d);&lt;!--CRLF--&gt;&lt;span style="color: #606060" id="lnum8"&gt;   8:&lt;/span&gt; }&lt;!--CRLF--&gt;&lt;span style="color: #606060" id="lnum9"&gt;   9:&lt;/span&gt; increase_data(&amp;amp;Data());&lt;!--CRLF--&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;到&lt;/p&gt;&lt;div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 100%; padding-right: 4px; font-family: 'Courier New', courier, monospace; direction: ltr; font-size: 8pt; overflow: hidden; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"&gt;&lt;div style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: hidden; padding-top: 0px" id="codeSnippet"&gt;&lt;span style="color: #606060" id="lnum1"&gt;   1:&lt;/span&gt; &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;class&lt;/span&gt; DataWorker&lt;!--CRLF--&gt;&lt;span style="color: #606060" id="lnum2"&gt;   2:&lt;/span&gt; {&lt;!--CRLF--&gt;&lt;span style="color: #606060" id="lnum3"&gt;   3:&lt;/span&gt;     &lt;span style="color: #0000ff"&gt;private&lt;/span&gt; &lt;span style="color: #0000ff"&gt;int&lt;/span&gt; data;&lt;!--CRLF--&gt;&lt;span style="color: #606060" id="lnum4"&gt;   4:&lt;/span&gt;     &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;void&lt;/span&gt; Increase()&lt;!--CRLF--&gt;&lt;span style="color: #606060" id="lnum5"&gt;   5:&lt;/span&gt;     {&lt;!--CRLF--&gt;&lt;span style="color: #606060" id="lnum6"&gt;   6:&lt;/span&gt;         Console.WriteLine(&lt;span style="color: #006080"&gt;"对象调用，数据为： {0}"&lt;/span&gt;, ++data);&lt;!--CRLF--&gt;&lt;span style="color: #606060" id="lnum7"&gt;   7:&lt;/span&gt;     }&lt;!--CRLF--&gt;&lt;span style="color: #606060" id="lnum8"&gt;   8:&lt;/span&gt; }&lt;!--CRLF--&gt;&lt;span style="color: #606060" id="lnum9"&gt;   9:&lt;/span&gt; &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; DataWorker().Increase();&lt;!--CRLF--&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;把传统的数据和处理数据的函数封装起来，用DataWorker对象来表示，数据变成了对象的状态，函数变成了对象的方法（行为）。一个对象被我们点&amp;#8220;活&amp;#8221;了，它负责处理一件事情，把责任下放是点活对象的出发点--&amp;#8220;变化太快了，面面俱到的管理让我疲于奔命，你就负责处理这块事情吧，由你来应对这块事情的变化&amp;#8221;。&lt;/p&gt;&lt;h1 style="padding-bottom: 5px; background-color: gray; margin-top: 24px; padding-left: 5px; padding-right: 5px; margin-bottom: 12px; color: white; font-size: 26px; font-weight: normal; padding-top: 5px"&gt;替换&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;对象被我们点活了，它们各尽其责来处理自己的事情，程序处理被变成了一个个对象间的相互协作，如果有变化产生我们找到负责的对象，由它来处理变化。想法是完美的，可是具体到对象，它怎么来应对变化？修改自己的方法（行为）？&lt;/p&gt;&lt;p&gt;对象是我们点活的，责任是我们分配的，方法（行为）是我们指定的，发生变化了还要我们来修改它的方法（行为），那绕一圈点活它干嘛？和面向过程中直接修改对应的函数有啥区别？是的，可能方便在于比较容易定位到它，但是你修改了一个对象后，如何保证和它协作的别的对象没有意见，不会造反？&lt;/p&gt;&lt;p&gt;从现实来讲，作为一个老总，指派了一个区域经理来负责一块业务，负责的业务出现了问题，你会对它的业务指手画脚来重新教育他该怎么做么？不会的，不要让自己陷入泥潭，首先信任，不行就炒了他，换一个。&lt;/p&gt;&lt;p&gt;应对变化的关键点在于&lt;strong&gt;替换&lt;/strong&gt;，这样才不会使自己陷入细节。替，顶替，表示新对象可以承担旧对象的职责，对协作的别的对象没有影响。换，表示要能应对变化，更改处理责任的具体方法（行为）。这是一个共性和变性的描述，那么怎么用程序语言来表示？&lt;/p&gt;&lt;h1 style="padding-bottom: 5px; background-color: gray; margin-top: 24px; padding-left: 5px; padding-right: 5px; margin-bottom: 12px; color: white; font-size: 26px; font-weight: normal; padding-top: 5px"&gt;类&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;类是面向对象程序语言中的一个概念，表示具有相同行为对象的模板，类声明了对象的行为，它描述了该类对象能够做什么以及如何做的方法。一个类的不同对象具有相同的成员（属性、方法等），用类来表示对象的共性，那么怎么来表示变性呢？&lt;/p&gt;&lt;p&gt;类之间支持继承，可以用父类和子类来表示这层关系，用自然语言来形容，父类是子类一种更高程度的抽象，比如动物和哺乳动物。子类可以添加新的行为或者重新定义父类的行为来完成变化。允许子类来重定义父类的行为，在对象间的相互协作中尤为重要，可以把不同的子类对象都当做父类对象来看，这样可以屏蔽不同子类对象间的差异。在需求变化时，通过子类对象的替换来在不改变对象协作关系的情况下完成变化，这种特性也被称为多态。&lt;/p&gt;&lt;p&gt;封装，继承，多态，被称为面向对象技术中的三大机制，那么回到本文的主题，什么叫面向对象呢？&lt;/p&gt;&lt;h1 style="padding-bottom: 5px; background-color: gray; margin-top: 24px; padding-left: 5px; padding-right: 5px; margin-bottom: 12px; color: white; font-size: 26px; font-weight: normal; padding-top: 5px"&gt;面向对象&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;所谓面向对象，面向两个字很重要--&amp;#8220;我的眼里只有你&amp;#8221;，面向对象的哲学在于把软件（世界）看成是由各种各样具有特定职责的对象所组成，不同对象之间的相互作用和通讯构成了整个软件（世界）。以面向对象的角度去进行程序设计，需要至少以下三步：&lt;/p&gt;&lt;ol&gt;&lt;li&gt;发现（设计）对象； &lt;/li&gt;&lt;li&gt;确定对象的职责； &lt;/li&gt;&lt;li&gt;确定对象间的相互关系。&lt;/li&gt;&lt;/ol&gt;&lt;p&gt;按前面所提，类是具有相同行为对象的模板，通过同一个类创建的不同对象具有相同的行为，对象是类的一个具体例子（实例），我们面向对象设计程序时，一般从类的设计开始。&lt;/p&gt;&lt;h1 style="padding-bottom: 5px; background-color: gray; margin-top: 24px; padding-left: 5px; padding-right: 5px; margin-bottom: 12px; color: white; font-size: 26px; font-weight: normal; padding-top: 5px"&gt;类的设计&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;类通常情况下是自然世界中一个概念的描述，比方说Person类通常对应人，这种软件和自然世界中的对应关系使我们可以尽可能运用人类的自然思维方式去解决问题。那么如何发现类呢？一个最简单的办法就是把我们熟知的自然概念直接抽象为类，比方说一个图书馆借书的程序，管理员，书，借书者，我们可以很容易想出一系列的概念，这些名词概念来自于我们对生活对该领域的了解。把我们熟悉的名词（概念）直接抽象为类，把动词抽象为该类的行为，这是一种最粗糙的类设计方法。这种设计比较容易下手，但是也会出现一些问题：&lt;/p&gt;&lt;ol&gt;&lt;li&gt;实现性，事物分抽象事物和具体事物两种，程序设计中用类的实例（对象）来表示一个具体事物。对于人来说，管理员，借书者都是人，同一个人可以充当不同角色，一个人可以通过学习具备一些能力并且通过经验积累来优化自己的能力。那么如何来设计这样一个类，让该类可以具备责任并自适应变化？ &lt;/li&gt;&lt;li&gt;目的性，现实世界中，解决一个领域的软件总会遇见各种各样的概念，那么需要把这些概念全部抽象为类么？面向对象就是把所有概念全部类化？&lt;/li&gt;&lt;/ol&gt;&lt;p&gt;对第一点来说，这是一个理想状态，大多数面向对象语言都是静态语言，如C#/Java/C++等，类作为对象的模板，既确定了该类对象的功能，在编译后又决定了对象的内存模型。静态语言使用继承，接口来完成类的扩展，相比动态语言，静态语言在运行速度，类型安全上有着很大优势，但由于类的扩展性是在编译期决定的，要应对变化就需要在类的设计上多下功夫。&lt;/p&gt;&lt;p&gt;针对第二点，这个前面已经提到了，引入对象的唯一原因是具有责任，应对变化，让它&amp;#8220;活&amp;#8221;起来，是为了让我们更轻松的生活，面向对象是一种方法观，程序执行后仍然被编译成一条条的过程语句执行。不要舍本逐末，来总结一下面向对象的设计经验。&lt;/p&gt;&lt;h1 style="padding-bottom: 5px; background-color: gray; margin-top: 24px; padding-left: 5px; padding-right: 5px; margin-bottom: 12px; color: white; font-size: 26px; font-weight: normal; padding-top: 5px"&gt;设计模式&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;设计模式，这里的全称应该是面向对象设计模式，我们熟知的设计模式，通常指GOF定义的23种设计模式。每种模式都有一个对应的名字，按种类可分为创建型，结构型和行为型三类。&lt;/p&gt;&lt;p&gt;介绍面向对象设计模式的文章也很多，模式，按Alexander的经典定义，指在某一背景下某个问题的一种解决方案。这里的解决方案指细节，某一背景下某个问题才是难点，深刻理解&amp;#8220;什么时候，什么场合用&amp;#8221;比&amp;#8220;如何用&amp;#8221;更重要，既然是面向对象设计模式，先从对象创建说起。&lt;/p&gt;&lt;p&gt;面向对象是为了适应变化，变化无处不在：&lt;/p&gt;&lt;ol&gt;&lt;li&gt;对象的创建要能适应变化，它不会自己凭空跳出来，必须有其他对象来负责该对象的创建。通常用工厂对象（Factory）来负责对象的创建，在工厂的基类中定义创建对象的虚方法，由工厂的子类来具体化这个创建。 &lt;/li&gt;&lt;li&gt;对象间的组织结构要能适应变化，如一般大公司具有总经理-部门经理-项目经理-员工等职位，完成一件事情需要各部门各员工间的配合，混乱的组织结构会导致难以应对扩张，对象间职位不清等问题。 &lt;/li&gt;&lt;li&gt;对象的行为要能适应变化，为了完成责任，变化可能来自于各个方面，可能会受对象状态的影响，可能需要其他对象的协助等等。&lt;/li&gt;&lt;/ol&gt;&lt;p&gt;设计模式是一种经验的积累，面向对象设计模式的根本是为了应对对象变化，每种设计模式都对应了一类变化点。这就需要在实际运用中识别变化点，因地制宜的分析可否引入对应的设计模式来最佳化设计。&lt;/p&gt;&lt;h1 style="padding-bottom: 5px; background-color: gray; margin-top: 24px; padding-left: 5px; padding-right: 5px; margin-bottom: 12px; color: white; font-size: 26px; font-weight: normal; padding-top: 5px"&gt;后记&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;文章存在草稿里很久了，再接已经没有思路了，简略了描述一下后面的想法：&lt;/p&gt;&lt;ol&gt;&lt;li&gt;关于面向对象设计的方法：面向对象程序设计仍在发展之中，关于如何指导用户从面向对象角度分析和设计程序，四色原型分析方法，领域驱动建模思想，DCI架构等都是一些好的经验。当然，这些经验都是帮助我们更好的去设计程序的，要因地制宜，不要本末倒置，不看实际就选定了一种方法，再生搬硬套把需求塞进这些框框之中。 &lt;/li&gt;&lt;li&gt;关于面向对象设计的优点：前面列举了面向过程的一些好的经验（模块原则，组合原则，扩展原则等），是因为在很多介绍面向对象程序设计的文章中，往往夸大了面向对象设计的优点。这些好的思想原则是通用的，不仅仅是面向对象设计所独有的。面向对象程序设计的优点在于它契合了人们分析自然时概念化的思维方式，在解决真实生活问题时往往比较容易下手。 &lt;/li&gt;&lt;li&gt;关于面向对象设计的缺点：成也萧何败也萧何，如果我们正确分析了需求，找准了可能的变化点，设计出的类模型往往具有较高的价值。如果错误的假设了程序的逻辑，过细/忽略了可能的变化点，则设计出的程序可能会导致结构混乱，抽象过多/无法扩展等问题。面向对象程序设计多呼吁尽早的引入领域专家帮助分析建模，来防止错误的捏造对象导致事倍功半。 &lt;/li&gt;&lt;li&gt;关于面向对象设计的实践：变化是不断存在的，很难存在所谓的完美设计，即使有领域专家的帮助，也很难做到类完全对修改封闭，对扩展开放。随着开发的深入，重构是不可避免的，这里重构的作用既要适应变化，又要保证已有功能的正确性。关于这方面的实践，敏捷是比较热的词汇，敏捷的主张在于用简单的初始设计，然后小步的持续改进，通过TDD来确保每一步改进的正确性。要应对变化，就要预知变化，设计抽象来隔离变化，当然，过度的抽象也会增加软件的复杂度，一个简单的指导原则是，在不能预知变化或者变化不是十分剧烈前，不要过多设计，清晰胜于一切。 &lt;/li&gt;&lt;li&gt;关于面向对象设计和编程语言：众所周知，C++/JAVA/C#等是面向对象的语言，在语言层次提供了类的支持，但并不是这些面向对象语言写出来的一定是面向对象的程序，比如所谓的充血/贫血模型---对象的行为是否被封装在对象其中，还是由Service来提供。这里出现了很多的名字，DomainObject，ValueObject等等，抛去这些名字不谈，如果对象的行为由对象来提供，那么这个对象才真正&amp;#8220;活&amp;#8221;起来，否则它还是过程化的数据封装。但并不是这样做不好，面向对象设计不是万能药，错误点&amp;#8220;活&amp;#8221;了对象，不仅不会让你省心，还会让你更加操心。反过来C语言等面向过程语言也可以支持面向对象的思想，Windows的WNDCLASS就是一个很好的例子，换一个角度去讲，如果程序中出现了依赖倒置，依赖于抽象而不依赖于具体，这种抽象体现出来的就是面向对象的思想。&lt;/li&gt;&lt;/ol&gt;&lt;h1 style="padding-bottom: 5px; background-color: gray; margin-top: 24px; padding-left: 5px; padding-right: 5px; margin-bottom: 12px; color: white; font-size: 26px; font-weight: normal; padding-top: 5px"&gt;题外话&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;设计方面的话题总是显得空泛，设计能力的提升来自于经验，脱离了实际去谈设计模式无疑纸上谈兵。设计上面对应需求，下面对应编码，实际又为项目服务，受项目资源制约。好的设计来自于坚持和妥协，也许往大了说很多东西也如此，祝朋友们多点积累，少点折腾，谢谢。&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;div&gt;&lt;span style="line-height: 25px; color: #333333"&gt;&lt;span style="line-height: 25px; background-color: #ffffff; font-family: georgia; color: #333333"&gt;&lt;span style="padding-bottom: 0px; line-height: 21px; margin: 0px; padding-left: 0px; padding-right: 0px; font-family: 宋体; color: black; font-size: 9pt; padding-top: 0px"&gt;作者：&lt;/span&gt;&lt;span style="padding-bottom: 0px; line-height: 21px; margin: 0px; padding-left: 0px; padding-right: 0px; font-family: verdana, sans-serif; color: black; font-size: 9pt; padding-top: 0px"&gt;&lt;a style="border-bottom: 1px dashed; padding-bottom: 0px; margin: 0px; outline-style: none; outline-color: ; padding-left: 0px; padding-right: 0px; color: #3d81ee; text-decoration: none; padding-top: 0px" href="http://www.cnblogs.com/Zhouyongh" target="_blank"&gt;&lt;span style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; font-family: 宋体; color: #ff6600; text-decoration: none; padding-top: 0px"&gt;周永恒&lt;/span&gt;&lt;/a&gt; &lt;br style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px" /&gt;&lt;/span&gt;&lt;span style="padding-bottom: 0px; line-height: 21px; margin: 0px; padding-left: 0px; padding-right: 0px; font-family: 宋体; color: black; font-size: 9pt; padding-top: 0px"&gt;出处：&lt;/span&gt;&lt;span style="padding-bottom: 0px; line-height: 21px; margin: 0px; padding-left: 0px; padding-right: 0px; font-family: verdana, sans-serif; color: black; font-size: 9pt; padding-top: 0px"&gt;&lt;a style="border-bottom: 1px dashed; padding-bottom: 0px; margin: 0px; outline-style: none; outline-color: ; padding-left: 0px; padding-right: 0px; color: #3d81ee; text-decoration: none; padding-top: 0px" href="http://www.cnblogs.com/Zhouyongh" target="_blank"&gt;&lt;span style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; color: #ff6600; text-decoration: none; padding-top: 0px"&gt;http://www.cnblogs.com/Zhouyongh&lt;/span&gt;&lt;/a&gt; &lt;br style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px" /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;p&gt;&lt;span style="line-height: 25px; font-family: 宋体; color: #333333; font-size: 12px" class="Apple-style-span"&gt;本文版权归作者和博客园共有，欢迎转载，但未经作者同意必须保留此段声明，且在文章页面明显位置给出原文连接，否则保留追究法律责任的权利。&lt;/span&gt;&lt;/p&gt;&lt;img src="http://www.cnblogs.com/Zhouyongh/aggbug/2212217.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/Zhouyongh/archive/2012/02/16/2212217.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/Zhouyongh/archive/2011/08/31/2160433.html</id><title type="text">解析Caliburn.Micro（四）</title><summary type="text">继续来介绍Caliburn.Micro框架，主要介绍了Action+Convention这条主线，对WPF/Silverlight/WP7感兴趣的朋友们可以阅读本篇文章。</summary><published>2011-08-31T02:59:00Z</published><updated>2011-08-31T02:59:00Z</updated><author><name>周永恒</name><uri>http://www.cnblogs.com/Zhouyongh/</uri></author><link rel="alternate" href="http://www.cnblogs.com/Zhouyongh/archive/2011/08/31/2160433.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/Zhouyongh/archive/2011/08/31/2160433.html"/><content type="html">&lt;p&gt;书接前文，继续来介绍一下&lt;a href="http://caliburnmicro.codeplex.com/"&gt;Caliburn.Micro&lt;/a&gt;（CM）中的Convention。&lt;/p&gt; &lt;h1 style="padding-bottom: 5px; background-color: gray; margin-top: 24px; padding-left: 5px; padding-right: 5px; margin-bottom: 12px; color: white; font-size: 26px; font-weight: normal; padding-top: 5px"&gt;前言&lt;/strong&gt;&lt;/p&gt; &lt;p&gt;Caliburn.Micro这个系列也写了好几篇了，作为一个第三方的应用框架，关于细节的详尽介绍并不是第一位的，能快而准确的把握它的整体思路才是最重要的。Caliburn.Micro框架中包含了很多功能，有前面介绍过的Action，Convention，Coroutine（协同），EventAggregator（弱事件）等等。其中很多功能都是锦上添花之作，比如EventAggregator等，在Prism等框架中都有介绍，CM的核心思路是它的Action以及Convention，详细的说一下这条主线。&lt;/p&gt; &lt;h1 style="padding-bottom: 5px; background-color: gray; margin-top: 24px; padding-left: 5px; padding-right: 5px; margin-bottom: 12px; color: white; font-size: 26px; font-weight: normal; padding-top: 5px"&gt;CM主线&lt;/strong&gt;&lt;/p&gt; &lt;p&gt;Caliburn.Micro的定位是一个轻量级的MVVM框架。作为MVVM，View和ViewModel之间用DataContext关联，View通过Binding和Command把操作传递给ViewModel并根据ViewModel中绑定属性的变化来自动刷新。用一个表格来对比一下Caliburn.Micro和通用MVVM框架的不同：&lt;/p&gt; &lt;table border="1" cellspacing="0" cellpadding="2" width="400"&gt; &lt;tbody&gt; &lt;tr&gt; &lt;td valign="top" width="133"&gt;特性&lt;/td&gt; &lt;td valign="top" width="133"&gt;普通MVVM框架&lt;/td&gt; &lt;td valign="top" width="133"&gt;Caliburn.Micro&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td valign="top" width="133"&gt;自动关联View和ViewModel（通过View的DataContext）。&lt;/td&gt; &lt;td valign="top" width="133"&gt;不支持&lt;/td&gt; &lt;td valign="top" width="133"&gt;支持，使用NameTransformer&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td valign="top" width="133"&gt;Command&lt;/td&gt; &lt;td valign="top" width="133"&gt;支持，推荐使用Command&lt;/td&gt; &lt;td valign="top" width="133"&gt;不支持，使用Action作为替代方案。&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td valign="top" width="133"&gt;Binding&lt;/td&gt; &lt;td valign="top" width="133"&gt;支持，推荐使用Binding。&lt;/td&gt; &lt;td valign="top" width="133"&gt;支持，可以使用Convention作为替代方案。&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td valign="top" width="133"&gt;Validation，StringFormat，Converter，UpdateSourceTrigger&lt;/td&gt; &lt;td valign="top" width="133"&gt;支持，使用Binding的对应机制&lt;/td&gt; &lt;td valign="top" width="133"&gt;支持，可以使用Convention作为替代方案。&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt; &lt;p&gt;举个简单的例子来对比：&lt;/p&gt; &lt;p&gt;普通MVVM框架：&lt;/p&gt; &lt;div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 100%; padding-right: 4px; font-family: 'Courier New', courier, monospace; direction: ltr; font-size: 8pt; overflow: hidden; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"&gt; &lt;div style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: hidden; padding-top: 0px" id="codeSnippet"&gt;&lt;span style="color: #606060" id="lnum1"&gt;   1:&lt;/span&gt; &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;Button&lt;/span&gt; &lt;span style="color: #ff0000"&gt;Command&lt;/span&gt;&lt;span style="color: #0000ff"&gt;="{Binding Path=ChangeNameCommand}"&lt;/span&gt;&lt;span style="color: #0000ff"&gt;/&amp;gt;&lt;/span&gt;&lt;!--CRLF--&gt;&lt;span style="color: #606060" id="lnum2"&gt;   2:&lt;/span&gt; &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;TextBox&lt;/span&gt; &lt;span style="color: #ff0000"&gt;Text&lt;/span&gt;&lt;span style="color: #0000ff"&gt;="{Binding Path=UserName}"&lt;/span&gt;&lt;span style="color: #0000ff"&gt;/&amp;gt;&lt;/span&gt;&lt;!--CRLF--&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;使用Caliburn.Micro的框架&lt;/p&gt;&lt;div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 100%; padding-right: 4px; font-family: 'Courier New', courier, monospace; direction: ltr; font-size: 8pt; overflow: hidden; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"&gt;&lt;div style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: hidden; padding-top: 0px" id="codeSnippet"&gt;&lt;span style="color: #606060" id="lnum1"&gt;   1:&lt;/span&gt; &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;Button&lt;/span&gt; &lt;span style="color: #ff0000"&gt;x:Name&lt;/span&gt;&lt;span style="color: #0000ff"&gt;="ChangeName"&lt;/span&gt;&lt;span style="color: #0000ff"&gt;/&amp;gt;&lt;/span&gt;&lt;!--CRLF--&gt;&lt;span style="color: #606060" id="lnum2"&gt;   2:&lt;/span&gt; &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;TextBox&lt;/span&gt; &lt;span style="color: #ff0000"&gt;x:Name&lt;/span&gt;&lt;span style="color: #0000ff"&gt;="UserName"&lt;/span&gt;&lt;span style="color: #0000ff"&gt;/&amp;gt;&lt;/span&gt;&lt;!--CRLF--&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;对应的ViewModel：&lt;/p&gt;&lt;p&gt;&lt;a href="http://images.cnblogs.com/cnblogs_com/Zhouyongh/201108/201108311050509728.png"&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="Capture" border="0" alt="Capture" src="http://images.cnblogs.com/cnblogs_com/Zhouyongh/201108/201108311050508332.png" width="229" height="137" /&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;使用了Caliburn.Micro后，只需要设置Button和TextBox的Name，使它匹配到ViewModel对应属性和方法的名字，CM会自动设置绑定以及Button方法的调用。&lt;/p&gt;&lt;p&gt;这个是CM设计的一个本意，使View和ViewModel之间的调用更加简单，只需要设定好对应的名字，其他的由CM来搞定。&lt;/p&gt;&lt;h1 style="padding-bottom: 5px; background-color: gray; margin-top: 24px; padding-left: 5px; padding-right: 5px; margin-bottom: 12px; color: white; font-size: 26px; font-weight: normal; padding-top: 5px"&gt;Command与Action&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;WPF中定义了Command机制，接口是ICommand，有Execute和CanExecute两个方法，并且提供了CommandParameter作为调用参数。使用Command模式，可以把执行操作的对象和处理操作的对象进行解耦，WPF这个思路是很好的，在具体实现上还存在一些不足。&lt;/p&gt;&lt;p&gt;WPF中一些控件提供了Command属性，允许你加入具体操作的ICommand。Command的触发是基于Routed Event的，比如Button就是在OnClick时触发了Command的执行。WPF在很多控件上都实现了Command，比如Button等，但还不够完全，像ComboBox等控件就没有Command。&lt;/p&gt;&lt;p&gt;一个Command只能响应一个Routed Event事件，对于默认的控件，比如Button等，它的响应事件是写死的（Click）。WPF在控件上提供了CommandBindings允许添加多个Command，但使用CommandBindings的写法很繁琐，对于MVVM模式的支持也不是太好。为了更好的支持MVVM模式，Blend提出了TriggerAction来更简单的添加Command，如：&lt;/p&gt;&lt;div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 100%; padding-right: 4px; font-family: 'Courier New', courier, monospace; direction: ltr; font-size: 8pt; overflow: hidden; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"&gt;&lt;div style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: hidden; padding-top: 0px" id="codeSnippet"&gt;&lt;span style="color: #606060" id="lnum1"&gt;   1:&lt;/span&gt; &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;Button&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;!--CRLF--&gt;&lt;span style="color: #606060" id="lnum2"&gt;   2:&lt;/span&gt;       &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;i:Interaction.Triggers&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;!--CRLF--&gt;&lt;span style="color: #606060" id="lnum3"&gt;   3:&lt;/span&gt;           &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;i:EventTrigger&lt;/span&gt; &lt;span style="color: #ff0000"&gt;EventName&lt;/span&gt;&lt;span style="color: #0000ff"&gt;="Click"&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;!--CRLF--&gt;&lt;span style="color: #606060" id="lnum4"&gt;   4:&lt;/span&gt;               &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;i:ExecuteCommandAction&lt;/span&gt; &lt;span style="color: #ff0000"&gt;TargetCommand&lt;/span&gt;&lt;span style="color: #0000ff"&gt;="LoginCommand"&lt;/span&gt;&lt;span style="color: #0000ff"&gt;/&amp;gt;&lt;/span&gt;&lt;!--CRLF--&gt;&lt;span style="color: #606060" id="lnum5"&gt;   5:&lt;/span&gt;           &lt;span style="color: #0000ff"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000"&gt;i:EventTrigger&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;!--CRLF--&gt;&lt;span style="color: #606060" id="lnum6"&gt;   6:&lt;/span&gt;       &lt;span style="color: #0000ff"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000"&gt;i:Interaction.Triggers&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;!--CRLF--&gt;&lt;span style="color: #606060" id="lnum7"&gt;   7:&lt;/span&gt; &lt;span style="color: #0000ff"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000"&gt;Button&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;!--CRLF--&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;这里指明了Command的触发前提是Click事件发生，触发后执行对应ViewModel的LoginCommand。&lt;/p&gt;&lt;p&gt;CM的Action就是基于Blend的TriggerAction，它的ActionMessage继承自TriggerAction&amp;lt;FrameworkElement&amp;gt;，不同之处在于它没有调用ViewModel中的Command，而是直接用反射拿到了对应ViewModel中的方法，去执行方法了。&lt;/p&gt;&lt;h1 style="padding-bottom: 5px; background-color: gray; margin-top: 24px; padding-left: 5px; padding-right: 5px; margin-bottom: 12px; color: white; font-size: 26px; font-weight: normal; padding-top: 5px"&gt;Action与Convention&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;为了使用简单，CM中的Action可以不指定方法的名字，它会通过控件的名字（Name）来和ViewModel中的属性、方法进行匹配。关于Action的具体使用，请参见&lt;a href="http://www.cnblogs.com/Zhouyongh/archive/2011/04/22/2018989.html"&gt;第一篇文章&lt;/a&gt;。我们讨论框架的设计，这个设计不会凭空出现，设计出了ActionMessage来替代Command，我们来看看接下来会出现的问题。&lt;/p&gt;&lt;ol&gt;&lt;li&gt;CM在Action的设计处采用了一种傻瓜式的操作思路，只需要你设计控件的名字（Name），其他的都用智能匹配帮你解决。既然是智能的模式，那这个智能就是控制点，控件的哪些属性需要智能使用绑定，如何保证这个智能性足够智能，使用了它并不会影响老的设计实现。 &lt;/li&gt;&lt;li&gt;WPF中的Command和Binding都是它的亮点，使用了CM，代码简洁了，Command和Binding都不见了。如何保证原有的一些功能：Command的CanExecute判断，Bindng的Validation，StringFormat，Converter等等， &lt;/li&gt;&lt;li&gt;复杂性与灵活性，功能强大但是代码众多的框架是让人望而生畏的，简洁明快但是缺乏扩展的框架也是不让人满意的，如何达到这样一个平衡性也是一个挑战。&lt;/li&gt;&lt;/ol&gt;&lt;p&gt;为了解决这些问题，CM引入了Convention这个概念。&lt;/p&gt;&lt;h1 style="padding-bottom: 5px; background-color: gray; margin-top: 24px; padding-left: 5px; padding-right: 5px; margin-bottom: 12px; color: white; font-size: 26px; font-weight: normal; padding-top: 5px"&gt;ElementConvention&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;关于如何自动匹配View和ViewModel，请参见&lt;a href="http://www.cnblogs.com/Zhouyongh/archive/2011/07/20/2111716.html"&gt;前文&lt;/a&gt;。这里主要来介绍ElementConvention，简略来说，它是为了解决智能性而推出的，是指导具体类型Convention的处理描述。前面我们看到，使用&lt;/p&gt;&lt;div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 100%; padding-right: 4px; font-family: 'Courier New', courier, monospace; direction: ltr; font-size: 8pt; overflow: hidden; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"&gt;&lt;div style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: hidden; padding-top: 0px" id="codeSnippet"&gt;&lt;span style="color: #606060" id="lnum1"&gt;   1:&lt;/span&gt; &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;TextBox&lt;/span&gt; &lt;span style="color: #ff0000"&gt;x:Name&lt;/span&gt;&lt;span style="color: #0000ff"&gt;="UserName"&lt;/span&gt;&lt;span style="color: #0000ff"&gt;/&amp;gt;&lt;/span&gt;&lt;!--CRLF--&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;CM会自动把TextBox的Text绑定到ViewModel的UserName属性上，CM在这里做的事情有二：一，它需要根据控件的类型（TextBox）来决定对于控件的哪个属性使用绑定。二，它需要根据控件的名字来做智能匹配。关于第二点，稍后再来介绍，先来看看对于不同类型的控件，CM是如何控制的。&lt;/p&gt;&lt;p&gt;CM使用ElementConvention来做Convention处理的类型描述，CM提供了ConventionManager这个静态类允许操作ElementConvention。ElementConvention如下：&lt;/p&gt;&lt;div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 100%; padding-right: 4px; font-family: 'Courier New', courier, monospace; direction: ltr; font-size: 8pt; overflow: hidden; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"&gt;&lt;div style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: hidden; padding-top: 0px" id="codeSnippet"&gt;&lt;span style="color: #606060" id="lnum1"&gt;   1:&lt;/span&gt; &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;class&lt;/span&gt; ElementConvention&lt;!--CRLF--&gt;&lt;span style="color: #606060" id="lnum2"&gt;   2:&lt;/span&gt; {&lt;!--CRLF--&gt;&lt;span style="color: #606060" id="lnum3"&gt;   3:&lt;/span&gt;     &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; Type ElementType;&lt;!--CRLF--&gt;&lt;span style="color: #606060" id="lnum4"&gt;   4:&lt;/span&gt;     &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;string&lt;/span&gt; ParameterProperty;&lt;!--CRLF--&gt;&lt;span style="color: #606060" id="lnum5"&gt;   5:&lt;/span&gt;     &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; Func&amp;lt;DependencyObject, DependencyProperty&amp;gt; GetBindableProperty;&lt;!--CRLF--&gt;&lt;span style="color: #606060" id="lnum6"&gt;   6:&lt;/span&gt;     &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; Func&amp;lt;System.Windows.Interactivity.TriggerBase&amp;gt; CreateTrigger;&lt;!--CRLF--&gt;&lt;span style="color: #606060" id="lnum7"&gt;   7:&lt;/span&gt; }&lt;!--CRLF--&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;以TextBox为例，其中ElementType是它的类型（TextBox），ParameterProperty是作用的Property（Text），GetBindableProperty是一个Func函数，对于TextBox来说返回TextProperty，CreateTrigger返回触发事件（TextChanged）。&lt;/p&gt;&lt;p&gt;ConventionManager默认提供了一些类型的处理描述，如在ConventionManager的静态函数中：&lt;/p&gt;&lt;div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 100%; padding-right: 4px; font-family: 'Courier New', courier, monospace; direction: ltr; font-size: 8pt; overflow: hidden; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"&gt;&lt;div style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: hidden; padding-top: 0px" id="codeSnippet"&gt;&lt;span style="color: #606060" id="lnum1"&gt;   1:&lt;/span&gt; AddElementConvention&amp;lt;ButtonBase&amp;gt;(ButtonBase.ContentProperty, &lt;span style="color: #006080"&gt;"DataContext"&lt;/span&gt;, &lt;span style="color: #006080"&gt;"Click"&lt;/span&gt;);&lt;!--CRLF--&gt;&lt;span style="color: #606060" id="lnum2"&gt;   2:&lt;/span&gt; AddElementConvention&amp;lt;TextBox&amp;gt;(TextBox.TextProperty, &lt;span style="color: #006080"&gt;"Text"&lt;/span&gt;, &lt;span style="color: #006080"&gt;"TextChanged"&lt;/span&gt;);&lt;!--CRLF--&gt;&lt;span style="color: #606060" id="lnum3"&gt;   3:&lt;/span&gt; AddElementConvention&amp;lt;TextBlock&amp;gt;(TextBlock.TextProperty, &lt;span style="color: #006080"&gt;"Text"&lt;/span&gt;, &lt;span style="color: #006080"&gt;"DataContextChanged"&lt;/span&gt;);&lt;!--CRLF--&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;可以调用ConventionManager的AddElementConvention方法来加入新类型的处理描述，或者更改原有的ElementConvention。&lt;/p&gt;&lt;h1 style="padding-bottom: 5px; background-color: gray; margin-top: 24px; padding-left: 5px; padding-right: 5px; margin-bottom: 12px; color: white; font-size: 26px; font-weight: normal; padding-top: 5px"&gt;Convention&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;讲过了Convention的处理描述（ElementConvention），来谈一下具体的Convention过程。&lt;/p&gt;&lt;p&gt;整个Convention过程是从View和ViewModel的Bind开始的：&lt;/p&gt;&lt;ol&gt;&lt;li&gt;手动或CM自动调用ViewModelBinder的Bind方法（传入对应的View和ViewModel），CM会使用View.GetApplyConventions（View）方法，来确定是否要在该View上使用Convention。如果不希望使用CM的Convention功能，可以在View上设置附加属性View.SetApplyConventions为False或者设置全局标志ViewModelBinder.ApplyConventionsByDefault为False，取消Convention。 &lt;/li&gt;&lt;li&gt;默认是开启Convention功能的，开始进入View的Convention，遍历View的VisualTree，获得所有有名字的控件。 &lt;/li&gt;&lt;li&gt;对这些有名字的控件使用Convention，Convention分两类，ActionConvention和PropertyConvention，Action指方法调用，Property指属性绑定。 &lt;/li&gt;&lt;li&gt;如果使用AddElementConvention时，最后一个参数传入了触发事件Trigger的名字（Click，TextChanged）等，证明该类型控件是可以有ActionConvention的。CM会用控件的名字来匹配ViewModel中所有公共方法的名字，如果存在相同则对它使用ActionConvention。如前面的Button-&amp;gt;ChangeName匹配ViewModel对应方法的名字，这个方法被触发的事件是AddElementConvention注册的Click事件。 &lt;div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 100%; padding-right: 4px; font-family: 'Courier New', courier, monospace; direction: ltr; font-size: 8pt; overflow: hidden; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"&gt;&lt;div style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: hidden; padding-top: 0px" id="codeSnippet"&gt;&lt;span style="color: #606060" id="lnum1"&gt;   1:&lt;/span&gt; &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;Button&lt;/span&gt; &lt;span style="color: #ff0000"&gt;x:Name&lt;/span&gt;&lt;span style="color: #0000ff"&gt;="ChangeName"&lt;/span&gt; &lt;span style="color: #0000ff"&gt;/&amp;gt;&lt;/span&gt;&lt;!--CRLF--&gt;&lt;/div&gt;&lt;/div&gt;&lt;/li&gt;&lt;li&gt;如果使用AddElementConvention时，第二个参数传入了属性名字，则对该类型控件使用PropertyConvention，方法与上面类似，用控件的名字匹配ViewModel中所有公共属性的名字，如果存在则设置绑定。&lt;/li&gt;&lt;/ol&gt;&lt;h1 style="padding-bottom: 5px; background-color: gray; margin-top: 24px; padding-left: 5px; padding-right: 5px; margin-bottom: 12px; color: white; font-size: 26px; font-weight: normal; padding-top: 5px"&gt;Validate，StringFormat，Converter&amp;#8230;&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;如果对控件使用了PropertyConvention，相当于CM自动帮我们设置了属性绑定，那么Binding里原有的一些Validate，StringFormat，Converter怎么处理？&lt;/p&gt;&lt;p&gt;ConventionManager提供了SetBinding来做PropertyConvention，来看一下它的代码：&lt;/p&gt;&lt;div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 100%; padding-right: 4px; font-family: 'Courier New', courier, monospace; direction: ltr; font-size: 8pt; overflow: hidden; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"&gt;&lt;div style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: hidden; padding-top: 0px" id="codeSnippet"&gt;&lt;span style="color: #606060" id="lnum1"&gt;   1:&lt;/span&gt; &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;static&lt;/span&gt; Func&amp;lt;Type, &lt;span style="color: #0000ff"&gt;string&lt;/span&gt;, PropertyInfo, FrameworkElement, ElementConvention, &lt;span style="color: #0000ff"&gt;bool&lt;/span&gt;&amp;gt; SetBinding =&lt;!--CRLF--&gt;&lt;span style="color: #606060" id="lnum2"&gt;   2:&lt;/span&gt;     (viewModelType, path, property, element, convention) =&amp;gt; {&lt;!--CRLF--&gt;&lt;span style="color: #606060" id="lnum3"&gt;   3:&lt;/span&gt;         var bindableProperty = convention.GetBindableProperty(element);&lt;!--CRLF--&gt;&lt;span style="color: #606060" id="lnum4"&gt;   4:&lt;/span&gt;         &lt;span style="color: #0000ff"&gt;if&lt;/span&gt;(bindableProperty == &lt;span style="color: #0000ff"&gt;null&lt;/span&gt; || HasBinding(element, bindableProperty))&lt;!--CRLF--&gt;&lt;span style="color: #606060" id="lnum5"&gt;   5:&lt;/span&gt;             &lt;span style="color: #0000ff"&gt;return&lt;/span&gt; &lt;span style="color: #0000ff"&gt;false&lt;/span&gt;;&lt;!--CRLF--&gt;&lt;span style="color: #606060" id="lnum6"&gt;   6:&lt;/span&gt;&amp;nbsp; &lt;!--CRLF--&gt;&lt;span style="color: #606060" id="lnum7"&gt;   7:&lt;/span&gt;         var binding = &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; Binding(path);&lt;!--CRLF--&gt;&lt;span style="color: #606060" id="lnum8"&gt;   8:&lt;/span&gt;&amp;nbsp; &lt;!--CRLF--&gt;&lt;span style="color: #606060" id="lnum9"&gt;   9:&lt;/span&gt;         ApplyBindingMode(binding, property);&lt;!--CRLF--&gt;&lt;span style="color: #606060" id="lnum10"&gt;  10:&lt;/span&gt;         ApplyValueConverter(binding, bindableProperty, property);&lt;!--CRLF--&gt;&lt;span style="color: #606060" id="lnum11"&gt;  11:&lt;/span&gt;         ApplyStringFormat(binding, convention, property);&lt;!--CRLF--&gt;&lt;span style="color: #606060" id="lnum12"&gt;  12:&lt;/span&gt;         ApplyValidation(binding, viewModelType, property);&lt;!--CRLF--&gt;&lt;span style="color: #606060" id="lnum13"&gt;  13:&lt;/span&gt;         ApplyUpdateSourceTrigger(bindableProperty, element, binding, property);&lt;!--CRLF--&gt;&lt;span style="color: #606060" id="lnum14"&gt;  14:&lt;/span&gt;&amp;nbsp; &lt;!--CRLF--&gt;&lt;span style="color: #606060" id="lnum15"&gt;  15:&lt;/span&gt;         BindingOperations.SetBinding(element, bindableProperty, binding);&lt;!--CRLF--&gt;&lt;span style="color: #606060" id="lnum16"&gt;  16:&lt;/span&gt;&amp;nbsp; &lt;!--CRLF--&gt;&lt;span style="color: #606060" id="lnum17"&gt;  17:&lt;/span&gt;         &lt;span style="color: #0000ff"&gt;return&lt;/span&gt; &lt;span style="color: #0000ff"&gt;true&lt;/span&gt;;&lt;!--CRLF--&gt;&lt;span style="color: #606060" id="lnum18"&gt;  18:&lt;/span&gt;     };&lt;!--CRLF--&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;其中的ApplyBindingMode，ApplyValueConverter等等都是Func，允许你替换原有的实现加入你自己的处理，默认的处理都非常简单。也就是说，CM帮我们自动设置的属性绑定是最基本的绑定。CM在PropertyConvention上的处理是很简单的，如果你在属性上已经手动设置了Text={Binding Path=ChangeName}，那么CM会忽略这个属性。PropertyConvention只产生最基本的属性绑定，如果你希望让产生的绑定智能化你可以替换这些Func来加入你自己的处理。这也是CM整体的一个设计思路，做一些智能操作简化程序，这些操作可以开启或关闭，只做最基本的事不做多余，预留一些扩展性允许定制。&lt;/p&gt;&lt;h1 style="padding-bottom: 5px; background-color: gray; margin-top: 24px; padding-left: 5px; padding-right: 5px; margin-bottom: 12px; color: white; font-size: 26px; font-weight: normal; padding-top: 5px"&gt;总结&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;CM设计的最大成功处在于它的简洁和灵活，它可以很好的和其他一些框架合作，也可以比较方便的插入到原有的代码中。如果你已经有了自己的框架，不妨试着合并一下CM。关于CM其他的一些功能就不做更多介绍了，如有有什么疑问欢迎给我留言，也希望和朋友们多多交流，谢谢。&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;div&gt;&lt;span style="line-height: 25px; color: #333333"&gt;&lt;span style="line-height: 25px; background-color: #ffffff; font-family: georgia; color: #333333"&gt;&lt;span style="padding-bottom: 0px; line-height: 21px; margin: 0px; padding-left: 0px; padding-right: 0px; font-family: 宋体; color: black; font-size: 9pt; padding-top: 0px"&gt;作者：&lt;/span&gt;&lt;span style="padding-bottom: 0px; line-height: 21px; margin: 0px; padding-left: 0px; padding-right: 0px; font-family: verdana, sans-serif; color: black; font-size: 9pt; padding-top: 0px"&gt;&lt;a style="border-bottom: 1px dashed; padding-bottom: 0px; margin: 0px; outline-style: none; outline-color: ; padding-left: 0px; padding-right: 0px; color: #3d81ee; text-decoration: none; padding-top: 0px" href="http://www.cnblogs.com/Zhouyongh" target="_blank"&gt;&lt;span style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; font-family: 宋体; color: #ff6600; text-decoration: none; padding-top: 0px"&gt;周永恒&lt;/span&gt;&lt;/a&gt; &lt;br style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px" /&gt;&lt;/span&gt;&lt;span style="padding-bottom: 0px; line-height: 21px; margin: 0px; padding-left: 0px; padding-right: 0px; font-family: 宋体; color: black; font-size: 9pt; padding-top: 0px"&gt;出处：&lt;/span&gt;&lt;span style="padding-bottom: 0px; line-height: 21px; margin: 0px; padding-left: 0px; padding-right: 0px; font-family: verdana, sans-serif; color: black; font-size: 9pt; padding-top: 0px"&gt;&lt;a style="border-bottom: 1px dashed; padding-bottom: 0px; margin: 0px; outline-style: none; outline-color: ; padding-left: 0px; padding-right: 0px; color: #3d81ee; text-decoration: none; padding-top: 0px" href="http://www.cnblogs.com/Zhouyongh" target="_blank"&gt;&lt;span style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; color: #ff6600; text-decoration: none; padding-top: 0px"&gt;http://www.cnblogs.com/Zhouyongh&lt;/span&gt;&lt;/a&gt; &lt;br style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px" /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;p&gt;&lt;span style="line-height: 25px; font-family: 宋体; color: #333333; font-size: 12px" class="Apple-style-span"&gt;本文版权归作者和博客园共有，欢迎转载，但未经作者同意必须保留此段声明，且在文章页面明显位置给出原文连接，否则保留追究法律责任的权利。&lt;/span&gt;&lt;/p&gt;&lt;img src="http://www.cnblogs.com/Zhouyongh/aggbug/2160433.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/Zhouyongh/archive/2011/08/31/2160433.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/Zhouyongh/archive/2011/08/01/2123610.html</id><title type="text">深入WPF--Style</title><summary type="text">继续这个系列，深入介绍WPF中的Style，Silverlight也可以作为参考，希望能在Style这个点上，把它讲透。</summary><published>2011-08-01T04:07:00Z</published><updated>2011-08-01T04:07:00Z</updated><author><name>周永恒</name><uri>http://www.cnblogs.com/Zhouyongh/</uri></author><link rel="alternate" href="http://www.cnblogs.com/Zhouyongh/archive/2011/08/01/2123610.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/Zhouyongh/archive/2011/08/01/2123610.html"/><content type="html">&lt;blockquote style='border:2px solid #EFEFEF;color:#333333;padding:5px 10px;'&gt; &lt;p align="left"&gt;&lt;a href="http://msdn.microsoft.com/zh-cn/library/system.windows.style.aspx"&gt;Style&lt;/a&gt; 用来在类型的不同实例之间共享属性、资源和事件处理程序，您可以将 &lt;a href="http://msdn.microsoft.com/zh-cn/library/system.windows.style.aspx"&gt;Style&lt;/a&gt; 看作是将一组属性值应用到多个元素的捷径。 &lt;/p&gt;&lt;/blockquote&gt; &lt;p&gt;这是MSDN上对Style的描述，翻译的还算中规中矩。Style（样式），简单来说，就是一种对属性值的批处理，类似于Html的CSS，可以快速的设置一系列属性值到UI元素。&lt;/p&gt; &lt;h1 style="padding-bottom: 5px; background-color: gray; margin-top: 24px; padding-left: 5px; padding-right: 5px; margin-bottom: 12px; color: white; font-size: 26px; font-weight: normal; padding-top: 5px"&gt;示例&lt;/strong&gt;&lt;/p&gt; &lt;p&gt;一个最简单的Style的例子：&lt;/p&gt; &lt;div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 100%; padding-right: 4px; font-family: 'Courier New', courier, monospace; direction: ltr; font-size: 8pt; overflow: hidden; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"&gt; &lt;div style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: hidden; padding-top: 0px" id="codeSnippet"&gt;&lt;span style="color: #606060" id="lnum1"&gt;   1:&lt;/span&gt; &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;Window&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;!--CRLF--&gt;&lt;span style="color: #606060" id="lnum2"&gt;   2:&lt;/span&gt;     &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;Grid&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;!--CRLF--&gt;&lt;span style="color: #606060" id="lnum3"&gt;   3:&lt;/span&gt;         &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;Grid.Resources&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;!--CRLF--&gt;&lt;span style="color: #606060" id="lnum4"&gt;   4:&lt;/span&gt;             &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;Style&lt;/span&gt; &lt;span style="color: #ff0000"&gt;TargetType&lt;/span&gt;&lt;span style="color: #0000ff"&gt;="{x:Type Button}"&lt;/span&gt; &lt;span style="color: #ff0000"&gt;x:Key&lt;/span&gt;&lt;span style="color: #0000ff"&gt;="ButtonStyle"&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;!--CRLF--&gt;&lt;span style="color: #606060" id="lnum5"&gt;   5:&lt;/span&gt;                 &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;Setter&lt;/span&gt; &lt;span style="color: #ff0000"&gt;Property&lt;/span&gt;&lt;span style="color: #0000ff"&gt;="Height"&lt;/span&gt; &lt;span style="color: #ff0000"&gt;Value&lt;/span&gt;&lt;span style="color: #0000ff"&gt;="22"&lt;/span&gt;&lt;span style="color: #0000ff"&gt;/&amp;gt;&lt;/span&gt;&lt;!--CRLF--&gt;&lt;span style="color: #606060" id="lnum6"&gt;   6:&lt;/span&gt;                 &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;Setter&lt;/span&gt; &lt;span style="color: #ff0000"&gt;Property&lt;/span&gt;&lt;span style="color: #0000ff"&gt;="Width"&lt;/span&gt; &lt;span style="color: #ff0000"&gt;Value&lt;/span&gt;&lt;span style="color: #0000ff"&gt;="60"&lt;/span&gt;&lt;span style="color: #0000ff"&gt;/&amp;gt;&lt;/span&gt;&lt;!--CRLF--&gt;&lt;span style="color: #606060" id="lnum7"&gt;   7:&lt;/span&gt;             &lt;span style="color: #0000ff"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000"&gt;Style&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;!--CRLF--&gt;&lt;span style="color: #606060" id="lnum8"&gt;   8:&lt;/span&gt;         &lt;span style="color: #0000ff"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000"&gt;Grid.Resources&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;!--CRLF--&gt;&lt;span style="color: #606060" id="lnum9"&gt;   9:&lt;/span&gt;         &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;Button&lt;/span&gt; &lt;span style="color: #ff0000"&gt;Content&lt;/span&gt;&lt;span style="color: #0000ff"&gt;="Button"&lt;/span&gt; &lt;span style="color: #ff0000"&gt;Style&lt;/span&gt;&lt;span style="color: #0000ff"&gt;="{StaticResource ButtonStyle}"&lt;/span&gt;&lt;span style="color: #0000ff"&gt;/&amp;gt;&lt;/span&gt;&lt;!--CRLF--&gt;&lt;span style="color: #606060" id="lnum10"&gt;  10:&lt;/span&gt;         &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;Button&lt;/span&gt; &lt;span style="color: #ff0000"&gt;Content&lt;/span&gt;&lt;span style="color: #0000ff"&gt;="Button"&lt;/span&gt; &lt;span style="color: #ff0000"&gt;Style&lt;/span&gt;&lt;span style="color: #0000ff"&gt;="{StaticResource ButtonStyle}"&lt;/span&gt; &lt;span style="color: #ff0000"&gt;Margin&lt;/span&gt;&lt;span style="color: #0000ff"&gt;="156,144,286,145"&lt;/span&gt; &lt;span style="color: #0000ff"&gt;/&amp;gt;&lt;/span&gt;&lt;!--CRLF--&gt;&lt;span style="color: #606060" id="lnum11"&gt;  11:&lt;/span&gt;     &lt;span style="color: #0000ff"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000"&gt;Grid&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;!--CRLF--&gt;&lt;span style="color: #606060" id="lnum12"&gt;  12:&lt;/span&gt; &lt;span style="color: #0000ff"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000"&gt;Window&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;!--CRLF--&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;关于Resources的知识，请参见&lt;a href="http://msdn.microsoft.com/en-us/library/ms742538.aspx"&gt;MSDN&lt;/a&gt;，这里创建了一个目标类型为Button的ButtonStyle，两个Button使用静态资源（&lt;a href="http://msdn.microsoft.com/en-us/library/ms750950.aspx"&gt;StaticResource&lt;/a&gt;）的查找方式来找到这个Style。Style中定义了Button的高度（Height）和宽度（Width），当使用了这个Style后，两个Button无需手动设置，即可自动设置它们的高度和宽度为ButtonStyle的预设值22和60。&lt;/p&gt;&lt;p&gt;Style作为属性，资源，事件的批处理，它提供了一种捷径来对控件进行快速设置，使用Style的好处有二：&lt;/p&gt;&lt;ol&gt;&lt;li&gt;把一些控件的通用设置抽出来变成Style，使这些控件具有统一的风格，修改Style中的属性值可以方便的作用在所有应用该Style的控件上。 &lt;/li&gt;&lt;li&gt;可以对同一类型控件定义多个Style，通过替换Style来方便的更改控件的样式。 &lt;/li&gt;&lt;/ol&gt;&lt;h1 style="padding-bottom: 5px; background-color: gray; margin-top: 24px; padding-left: 5px; padding-right: 5px; margin-bottom: 12px; color: white; font-size: 26px; font-weight: normal; padding-top: 5px"&gt;Style的元素&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;上面Style的例子中，Style内部使用了Setter来定义控件属性的预设值，Style不仅支持对属性的批处理，也可以共享资源和事件处理，如：&lt;/p&gt;&lt;div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 100%; padding-right: 4px; font-family: 'Courier New', courier, monospace; direction: ltr; font-size: 8pt; overflow: hidden; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"&gt;&lt;div style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: hidden; padding-top: 0px" id="codeSnippet"&gt;&lt;span style="color: #606060" id="lnum1"&gt;   1:&lt;/span&gt; &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;Window&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;!--CRLF--&gt;&lt;span style="color: #606060" id="lnum2"&gt;   2:&lt;/span&gt;     &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;Window.Resources&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;!--CRLF--&gt;&lt;span style="color: #606060" id="lnum3"&gt;   3:&lt;/span&gt;         &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;Style&lt;/span&gt; &lt;span style="color: #ff0000"&gt;TargetType&lt;/span&gt;&lt;span style="color: #0000ff"&gt;="{x:Type Button}"&lt;/span&gt; &lt;span style="color: #ff0000"&gt;x:Key&lt;/span&gt;&lt;span style="color: #0000ff"&gt;="ButtonStyle"&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;!--CRLF--&gt;&lt;span style="color: #606060" id="lnum4"&gt;   4:&lt;/span&gt;             &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;Style.Resources&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;!--CRLF--&gt;&lt;span style="color: #606060" id="lnum5"&gt;   5:&lt;/span&gt;                 &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;SolidColorBrush&lt;/span&gt; &lt;span style="color: #ff0000"&gt;x:Key&lt;/span&gt;&lt;span style="color: #0000ff"&gt;="brush"&lt;/span&gt; &lt;span style="color: #ff0000"&gt;Color&lt;/span&gt;&lt;span style="color: #0000ff"&gt;="Yellow"&lt;/span&gt;&lt;span style="color: #0000ff"&gt;/&amp;gt;&lt;/span&gt;&lt;!--CRLF--&gt;&lt;span style="color: #606060" id="lnum6"&gt;   6:&lt;/span&gt;             &lt;span style="color: #0000ff"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000"&gt;Style.Resources&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;!--CRLF--&gt;&lt;span style="color: #606060" id="lnum7"&gt;   7:&lt;/span&gt;             &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;Setter&lt;/span&gt; &lt;span style="color: #ff0000"&gt;Property&lt;/span&gt;&lt;span style="color: #0000ff"&gt;="Height"&lt;/span&gt; &lt;span style="color: #ff0000"&gt;Value&lt;/span&gt;&lt;span style="color: #0000ff"&gt;="22"&lt;/span&gt;&lt;span style="color: #0000ff"&gt;/&amp;gt;&lt;/span&gt;&lt;!--CRLF--&gt;&lt;span style="color: #606060" id="lnum8"&gt;   8:&lt;/span&gt;             &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;Setter&lt;/span&gt; &lt;span style="color: #ff0000"&gt;Property&lt;/span&gt;&lt;span style="color: #0000ff"&gt;="Width"&lt;/span&gt; &lt;span style="color: #ff0000"&gt;Value&lt;/span&gt;&lt;span style="color: #0000ff"&gt;="60"&lt;/span&gt;&lt;span style="color: #0000ff"&gt;/&amp;gt;&lt;/span&gt;&lt;!--CRLF--&gt;&lt;span style="color: #606060" id="lnum9"&gt;   9:&lt;/span&gt;             &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;EventSetter&lt;/span&gt; &lt;span style="color: #ff0000"&gt;Event&lt;/span&gt;&lt;span style="color: #0000ff"&gt;="Loaded"&lt;/span&gt; &lt;span style="color: #ff0000"&gt;Handler&lt;/span&gt;&lt;span style="color: #0000ff"&gt;="Button_Loaded"&lt;/span&gt;&lt;span style="color: #0000ff"&gt;/&amp;gt;&lt;/span&gt;&lt;!--CRLF--&gt;&lt;span style="color: #606060" id="lnum10"&gt;  10:&lt;/span&gt;         &lt;span style="color: #0000ff"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000"&gt;Style&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;!--CRLF--&gt;&lt;span style="color: #606060" id="lnum11"&gt;  11:&lt;/span&gt;     &lt;span style="color: #0000ff"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000"&gt;Window.Resources&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;!--CRLF--&gt;&lt;span style="color: #606060" id="lnum12"&gt;  12:&lt;/span&gt;     &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;x:Code&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;!--CRLF--&gt;&lt;span style="color: #606060" id="lnum13"&gt;  13:&lt;/span&gt;         &lt;span style="color: #0000ff"&gt;&amp;lt;!&lt;/span&gt;[CDATA[&lt;!--CRLF--&gt;&lt;span style="color: #606060" id="lnum14"&gt;  14:&lt;/span&gt;             void Button_Loaded(object sender, RoutedEventArgs e)&lt;!--CRLF--&gt;&lt;span style="color: #606060" id="lnum15"&gt;  15:&lt;/span&gt;             {&lt;!--CRLF--&gt;&lt;span style="color: #606060" id="lnum16"&gt;  16:&lt;/span&gt;                 MessageBox.Show((sender as Button).Name + " Loaded");&lt;!--CRLF--&gt;&lt;span style="color: #606060" id="lnum17"&gt;  17:&lt;/span&gt;             }&lt;!--CRLF--&gt;&lt;span style="color: #606060" id="lnum18"&gt;  18:&lt;/span&gt;         ]]&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;!--CRLF--&gt;&lt;span style="color: #606060" id="lnum19"&gt;  19:&lt;/span&gt;     &lt;span style="color: #0000ff"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000"&gt;x:Code&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;!--CRLF--&gt;&lt;span style="color: #606060" id="lnum20"&gt;  20:&lt;/span&gt;     &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;Grid&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;!--CRLF--&gt;&lt;span style="color: #606060" id="lnum21"&gt;  21:&lt;/span&gt;         &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;Button&lt;/span&gt; &lt;span style="color: #ff0000"&gt;x:Name&lt;/span&gt;&lt;span style="color: #0000ff"&gt;="button1"&lt;/span&gt; &lt;span style="color: #ff0000"&gt;Style&lt;/span&gt;&lt;span style="color: #0000ff"&gt;="{StaticResource ButtonStyle}"&lt;/span&gt; &lt;span style="color: #ff0000"&gt;Background&lt;/span&gt;&lt;span style="color: #0000ff"&gt;="{DynamicResource brush}"&lt;/span&gt;&lt;span style="color: #0000ff"&gt;/&amp;gt;&lt;/span&gt;&lt;!--CRLF--&gt;&lt;span style="color: #606060" id="lnum22"&gt;  22:&lt;/span&gt;         &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;Button&lt;/span&gt; &lt;span style="color: #ff0000"&gt;x:Name&lt;/span&gt;&lt;span style="color: #0000ff"&gt;="button2"&lt;/span&gt; &lt;span style="color: #ff0000"&gt;Style&lt;/span&gt;&lt;span style="color: #0000ff"&gt;="{StaticResource ButtonStyle}"&lt;/span&gt; &lt;span style="color: #ff0000"&gt;Background&lt;/span&gt;&lt;span style="color: #0000ff"&gt;="{DynamicResource brush}"&lt;/span&gt; &lt;span style="color: #ff0000"&gt;Margin&lt;/span&gt;&lt;span style="color: #0000ff"&gt;="156,144,286,145"&lt;/span&gt; &lt;span style="color: #0000ff"&gt;/&amp;gt;&lt;/span&gt;&lt;!--CRLF--&gt;&lt;span style="color: #606060" id="lnum23"&gt;  23:&lt;/span&gt;     &lt;span style="color: #0000ff"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000"&gt;Grid&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;!--CRLF--&gt;&lt;span style="color: #606060" id="lnum24"&gt;  24:&lt;/span&gt; &lt;span style="color: #0000ff"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000"&gt;Window&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;!--CRLF--&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;Style中定义了资源SolidColorBrush，定义了属性Height和Width，以及使用了EventSetter来定义了Loaded事件的处理。&lt;/p&gt;&lt;h1 style="padding-bottom: 5px; background-color: gray; margin-top: 24px; padding-left: 5px; padding-right: 5px; margin-bottom: 12px; color: white; font-size: 26px; font-weight: normal; padding-top: 5px"&gt;Trigger&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;Style使用了Setter和EventSetter来分别设置控件的属性和事件处理，Setter这个单词的含义是设置。Style在设计好了这两种设置后，又引入了更先进的思路：条件设置。&lt;/p&gt;&lt;p&gt;对于单纯的Setter：&amp;lt;Setter Property=&amp;#8221;Height&amp;#8221; Value=&amp;#8221;22&amp;#8221;&amp;gt;来说，含义浅显易懂：设置高度为22。条件设置的含义是，在某种条件下，去设置某个对象的某个值。&lt;/p&gt;&lt;p&gt;WPF引入了Trigger（触发器）来触发这个条件，它的写法是：&lt;/p&gt;&lt;div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 100%; padding-right: 4px; font-family: 'Courier New', courier, monospace; direction: ltr; font-size: 8pt; overflow: hidden; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"&gt;&lt;div style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: hidden; padding-top: 0px" id="codeSnippet"&gt;&lt;span style="color: #606060" id="lnum1"&gt;   1:&lt;/span&gt; &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;Style&lt;/span&gt; &lt;span style="color: #ff0000"&gt;TargetType&lt;/span&gt;&lt;span style="color: #0000ff"&gt;="{x:Type Button}"&lt;/span&gt; &lt;span style="color: #ff0000"&gt;x:Key&lt;/span&gt;&lt;span style="color: #0000ff"&gt;="ButtonStyle"&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;!--CRLF--&gt;&lt;span style="color: #606060" id="lnum2"&gt;   2:&lt;/span&gt;     &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;Setter&lt;/span&gt; &lt;span style="color: #ff0000"&gt;Property&lt;/span&gt;&lt;span style="color: #0000ff"&gt;="Width"&lt;/span&gt; &lt;span style="color: #ff0000"&gt;Value&lt;/span&gt;&lt;span style="color: #0000ff"&gt;="60"&lt;/span&gt;&lt;span style="color: #0000ff"&gt;/&amp;gt;&lt;/span&gt;&lt;!--CRLF--&gt;&lt;span style="color: #606060" id="lnum3"&gt;   3:&lt;/span&gt;     &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;Style.Triggers&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;!--CRLF--&gt;&lt;span style="color: #606060" id="lnum4"&gt;   4:&lt;/span&gt;         &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;Trigger&lt;/span&gt; &lt;span style="color: #ff0000"&gt;Property&lt;/span&gt;&lt;span style="color: #0000ff"&gt;="IsMouseOver"&lt;/span&gt; &lt;span style="color: #ff0000"&gt;Value&lt;/span&gt;&lt;span style="color: #0000ff"&gt;="True"&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;!--CRLF--&gt;&lt;span style="color: #606060" id="lnum5"&gt;   5:&lt;/span&gt;             &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;Setter&lt;/span&gt; &lt;span style="color: #ff0000"&gt;Property&lt;/span&gt;&lt;span style="color: #0000ff"&gt;="Width"&lt;/span&gt; &lt;span style="color: #ff0000"&gt;Value&lt;/span&gt;&lt;span style="color: #0000ff"&gt;="80"&lt;/span&gt;&lt;span style="color: #0000ff"&gt;/&amp;gt;&lt;/span&gt;&lt;!--CRLF--&gt;&lt;span style="color: #606060" id="lnum6"&gt;   6:&lt;/span&gt;         &lt;span style="color: #0000ff"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000"&gt;Trigger&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;!--CRLF--&gt;&lt;span style="color: #606060" id="lnum7"&gt;   7:&lt;/span&gt;     &lt;span style="color: #0000ff"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000"&gt;Style.Triggers&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;!--CRLF--&gt;&lt;span style="color: #606060" id="lnum8"&gt;   8:&lt;/span&gt; &lt;span style="color: #0000ff"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000"&gt;Style&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;!--CRLF--&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;这里Trigger的含义是，在Button的IsMouseOver属性被设置为True的条件下，设置Button的宽度（Width）为80。&lt;/p&gt;&lt;p&gt;在Style中，不需要指定Setter作用的对象（TargetName），默认作用的对象就是使用该Style的控件。Trigger，作为触发器，当触发时设置宽度为80，当IsMouseOver属性为False，也就是触发条件失效时，宽度回到默认Setter的设置值60。&lt;/p&gt;&lt;p&gt;WPF定义了五种Trigger来作为触发条件，分别是：Trigger，DataTrigger，MultiTrigger，MultiDataTrigger，EventTrigger，他们的触发条件分别是：&lt;/p&gt;&lt;ol&gt;&lt;li&gt;Trigger：以控件的属性作为触发条件，如前面的IsMouseOver为True的时候触发。 &lt;/li&gt;&lt;li&gt;DataTrigger：以控件DataContext的属性作为触发条件。 &lt;/li&gt;&lt;li&gt;MultiTrigger：以控件的多个属性作为触发条件。 &lt;/li&gt;&lt;li&gt;MultiDataTrigger：以控件DataContext的多个属性作为触发条件。 &lt;/li&gt;&lt;li&gt;EventTrigger：以RoutedEvent作为触发条件，当指定的路由事件Raise时触发。 &lt;/li&gt;&lt;/ol&gt;&lt;p&gt;关于这5种Trigger的具体使用，请参见&lt;a href="http://msdn.microsoft.com/en-us/library/ms745683.aspx"&gt;MSDN&lt;/a&gt;，这里就不详细介绍了。&lt;/p&gt;&lt;h1 style="padding-bottom: 5px; background-color: gray; margin-top: 24px; padding-left: 5px; padding-right: 5px; margin-bottom: 12px; color: white; font-size: 26px; font-weight: normal; padding-top: 5px"&gt;Implicit Style&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;上面的例子中，都是使用&lt;a href="http://msdn.microsoft.com/en-us/library/ms750950.aspx"&gt;StaticResource&lt;/a&gt;来设置Style的，当然，你也可以使用&lt;a href="http://msdn.microsoft.com/zh-cn/library/ms748942.aspx"&gt;DynamicResource&lt;/a&gt;来设置Style。这两种方式都需要你在XAML或者后台代码中手动注明，为了使用方便，WPF提出了隐式（Implicit） Style的方式允许自动设置Style到控件，如：&lt;/p&gt;&lt;div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 100%; padding-right: 4px; font-family: 'Courier New', courier, monospace; direction: ltr; font-size: 8pt; overflow: hidden; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"&gt;&lt;div style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: hidden; padding-top: 0px" id="codeSnippet"&gt;&lt;span style="color: #606060" id="lnum1"&gt;   1:&lt;/span&gt; &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;Window&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;!--CRLF--&gt;&lt;span style="color: #606060" id="lnum2"&gt;   2:&lt;/span&gt;     &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;Grid&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;!--CRLF--&gt;&lt;span style="color: #606060" id="lnum3"&gt;   3:&lt;/span&gt;         &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;Grid.Resources&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;!--CRLF--&gt;&lt;span style="color: #606060" id="lnum4"&gt;   4:&lt;/span&gt;             &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;Style&lt;/span&gt; &lt;span style="color: #ff0000"&gt;TargetType&lt;/span&gt;&lt;span style="color: #0000ff"&gt;="{x:Type Button}"&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;!--CRLF--&gt;&lt;span style="color: #606060" id="lnum5"&gt;   5:&lt;/span&gt;                 &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;Setter&lt;/span&gt; &lt;span style="color: #ff0000"&gt;Property&lt;/span&gt;&lt;span style="color: #0000ff"&gt;="Height"&lt;/span&gt; &lt;span style="color: #ff0000"&gt;Value&lt;/span&gt;&lt;span style="color: #0000ff"&gt;="22"&lt;/span&gt;&lt;span style="color: #0000ff"&gt;/&amp;gt;&lt;/span&gt;&lt;!--CRLF--&gt;&lt;span style="color: #606060" id="lnum6"&gt;   6:&lt;/span&gt;                 &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;Setter&lt;/span&gt; &lt;span style="color: #ff0000"&gt;Property&lt;/span&gt;&lt;span style="color: #0000ff"&gt;="Width"&lt;/span&gt; &lt;span style="color: #ff0000"&gt;Value&lt;/span&gt;&lt;span style="color: #0000ff"&gt;="60"&lt;/span&gt;&lt;span style="color: #0000ff"&gt;/&amp;gt;&lt;/span&gt;&lt;!--CRLF--&gt;&lt;span style="color: #606060" id="lnum7"&gt;   7:&lt;/span&gt;             &lt;span style="color: #0000ff"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000"&gt;Style&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;!--CRLF--&gt;&lt;span style="color: #606060" id="lnum8"&gt;   8:&lt;/span&gt;         &lt;span style="color: #0000ff"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000"&gt;Grid.Resources&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;!--CRLF--&gt;&lt;span style="color: #606060" id="lnum9"&gt;   9:&lt;/span&gt;         &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;Button&lt;/span&gt; &lt;span style="color: #ff0000"&gt;x:Name&lt;/span&gt;&lt;span style="color: #0000ff"&gt;="button1"&lt;/span&gt; &lt;span style="color: #ff0000"&gt;Style&lt;/span&gt;&lt;span style="color: #0000ff"&gt;="{x:Null}"&lt;/span&gt;&lt;span style="color: #0000ff"&gt;/&amp;gt;&lt;/span&gt;&lt;!--CRLF--&gt;&lt;span style="color: #606060" id="lnum10"&gt;  10:&lt;/span&gt;         &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;Button&lt;/span&gt; &lt;span style="color: #ff0000"&gt;x:Name&lt;/span&gt;&lt;span style="color: #0000ff"&gt;="button2"&lt;/span&gt; &lt;span style="color: #ff0000"&gt;Margin&lt;/span&gt;&lt;span style="color: #0000ff"&gt;="156,144,286,145"&lt;/span&gt; &lt;span style="color: #0000ff"&gt;/&amp;gt;&lt;/span&gt;&lt;!--CRLF--&gt;&lt;span style="color: #606060" id="lnum11"&gt;  11:&lt;/span&gt;         &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;Button&lt;/span&gt; &lt;span style="color: #ff0000"&gt;x:Name&lt;/span&gt;&lt;span style="color: #0000ff"&gt;="button3"&lt;/span&gt; &lt;span style="color: #ff0000"&gt;Margin&lt;/span&gt;&lt;span style="color: #0000ff"&gt;="196,144,0,145"&lt;/span&gt; &lt;span style="color: #0000ff"&gt;/&amp;gt;&lt;/span&gt;&lt;!--CRLF--&gt;&lt;span style="color: #606060" id="lnum12"&gt;  12:&lt;/span&gt;     &lt;span style="color: #0000ff"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000"&gt;Grid&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;!--CRLF--&gt;&lt;span style="color: #606060" id="lnum13"&gt;  13:&lt;/span&gt; &lt;span style="color: #0000ff"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000"&gt;Window&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;!--CRLF--&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;在Gird的Resource中定义Style时，没有给Style起名字（Key），这个Style会自动应用在Grid的所有子Button中，如果像button1一样在Button中显式定义了Style（这里设置了一个空值Null），那么这种隐式（Implicit）的Style会不起作用。&lt;/p&gt;&lt;h1 style="padding-bottom: 5px; background-color: gray; margin-top: 24px; padding-left: 5px; padding-right: 5px; margin-bottom: 12px; color: white; font-size: 26px; font-weight: normal; padding-top: 5px"&gt;深入Style&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;Style是一个不错的概念，作为一个Presentation的框架，把UI对象的结构，样式和行为分离这是一种很好的设计。Style也比较容易上手，像它的隐式（Implicit）Style的设计也是水到渠成的想法，但实际使用中也会出现一些问题。这些问题在WPF中也会经常遇见：概念不错，描述简单，前景美好，Bug稀奇古怪，要把这些问题说清楚，就要从根本来看，Style是个什么东西？&lt;/p&gt;&lt;p&gt;按照通常的想法，Style应该类似于一个Dictionary&amp;lt;string, object&amp;gt; setters，预存了属性的名字和预设值，然后作用到UI对象上。WPF在Style处的想法很多，围绕着几个关键技术也加入了很多功能，详细的介绍一下：&lt;/p&gt;&lt;h1 style="padding-bottom: 5px; background-color: gray; margin-top: 24px; padding-left: 5px; padding-right: 5px; margin-bottom: 12px; color: white; font-size: 26px; font-weight: normal; padding-top: 5px"&gt;Style &amp;amp; Dependency Property&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;Dependency Property（简称DP）是WPF的核心，Style就是基于Dependency Property的，关于DP的内幕，请参见&lt;a href="http://www.cnblogs.com/Zhouyongh/archive/2009/09/10/1564099.html"&gt;深入WPF--依赖属性&lt;/a&gt;。Style中的Setter就是作用在DP上的，如果你在控件中定义了一个CLR属性，Style是不能设置的。Dependency Property设计的精髓在于把字段的存取和对象（Dependency Object）剥离开，一个属性值内部用多个字段来存储，根据取值条件的优先级来决定当前属性应该取哪个字段。&lt;/p&gt;&lt;p&gt;Dependency Property取值条件的优先级是（从上到下优先级从低到高）：&lt;/p&gt;&lt;div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 100%; padding-right: 4px; font-family: 'Courier New', courier, monospace; direction: ltr; font-size: 8pt; overflow: hidden; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"&gt;&lt;div style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: hidden; padding-top: 0px" id="codeSnippet"&gt;&lt;span style="color: #606060" id="lnum1"&gt;   1:&lt;/span&gt; &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;enum&lt;/span&gt; BaseValueSource&lt;!--CRLF--&gt;&lt;span style="color: #606060" id="lnum2"&gt;   2:&lt;/span&gt; {&lt;!--CRLF--&gt;&lt;span style="color: #606060" id="lnum3"&gt;   3:&lt;/span&gt;     Unknown,&lt;!--CRLF--&gt;&lt;span style="color: #606060" id="lnum4"&gt;   4:&lt;/span&gt;     Default,&lt;!--CRLF--&gt;&lt;span style="color: #606060" id="lnum5"&gt;   5:&lt;/span&gt;     Inherited,&lt;!--CRLF--&gt;&lt;span style="color: #606060" id="lnum6"&gt;   6:&lt;/span&gt;     DefaultStyle,&lt;!--CRLF--&gt;&lt;span style="color: #606060" id="lnum7"&gt;   7:&lt;/span&gt;     DefaultStyleTrigger,&lt;!--CRLF--&gt;&lt;span style="color: #606060" id="lnum8"&gt;   8:&lt;/span&gt;     Style,&lt;!--CRLF--&gt;&lt;span style="color: #606060" id="lnum9"&gt;   9:&lt;/span&gt;     TemplateTrigger,&lt;!--CRLF--&gt;&lt;span style="color: #606060" id="lnum10"&gt;  10:&lt;/span&gt;     StyleTrigger,&lt;!--CRLF--&gt;&lt;span style="color: #606060" id="lnum11"&gt;  11:&lt;/span&gt;     ImplicitStyleReference,&lt;!--CRLF--&gt;&lt;span style="color: #606060" id="lnum12"&gt;  12:&lt;/span&gt;     ParentTemplate,&lt;!--CRLF--&gt;&lt;span style="color: #606060" id="lnum13"&gt;  13:&lt;/span&gt;     ParentTemplateTrigger,&lt;!--CRLF--&gt;&lt;span style="color: #606060" id="lnum14"&gt;  14:&lt;/span&gt;     Local&lt;!--CRLF--&gt;&lt;span style="color: #606060" id="lnum15"&gt;  15:&lt;/span&gt; }&lt;!--CRLF--&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;对于一个具体例子来说：&lt;/p&gt;&lt;div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 100%; padding-right: 4px; font-family: 'Courier New', courier, monospace; direction: ltr; font-size: 8pt; overflow: hidden; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"&gt;&lt;div style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: hidden; padding-top: 0px" id="codeSnippet"&gt;&lt;span style="color: #606060" id="lnum1"&gt;   1:&lt;/span&gt; &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;Window&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;!--CRLF--&gt;&lt;span style="color: #606060" id="lnum2"&gt;   2:&lt;/span&gt;     &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;Window.Resources&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;!--CRLF--&gt;&lt;span style="color: #606060" id="lnum3"&gt;   3:&lt;/span&gt;         &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;Style&lt;/span&gt; &lt;span style="color: #ff0000"&gt;TargetType&lt;/span&gt;&lt;span style="color: #0000ff"&gt;="{x:Type Button}"&lt;/span&gt; &lt;span style="color: #ff0000"&gt;x:Key&lt;/span&gt;&lt;span style="color: #0000ff"&gt;="ButtonStyle"&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;!--CRLF--&gt;&lt;span style="color: #606060" id="lnum4"&gt;   4:&lt;/span&gt;             &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;Setter&lt;/span&gt; &lt;span style="color: #ff0000"&gt;Property&lt;/span&gt;&lt;span style="color: #0000ff"&gt;="Width"&lt;/span&gt; &lt;span style="color: #ff0000"&gt;Value&lt;/span&gt;&lt;span style="color: #0000ff"&gt;="60"&lt;/span&gt;&lt;span style="color: #0000ff"&gt;/&amp;gt;&lt;/span&gt;&lt;!--CRLF--&gt;&lt;span style="color: #606060" id="lnum5"&gt;   5:&lt;/span&gt;             &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;Style.Triggers&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;!--CRLF--&gt;&lt;span style="color: #606060" id="lnum6"&gt;   6:&lt;/span&gt;                 &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;Trigger&lt;/span&gt; &lt;span style="color: #ff0000"&gt;Property&lt;/span&gt;&lt;span style="color: #0000ff"&gt;="IsMouseOver"&lt;/span&gt; &lt;span style="color: #ff0000"&gt;Value&lt;/span&gt;&lt;span style="color: #0000ff"&gt;="True"&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;!--CRLF--&gt;&lt;span style="color: #606060" id="lnum7"&gt;   7:&lt;/span&gt;                     &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;Setter&lt;/span&gt; &lt;span style="color: #ff0000"&gt;Property&lt;/span&gt;&lt;span style="color: #0000ff"&gt;="Width"&lt;/span&gt; &lt;span style="color: #ff0000"&gt;Value&lt;/span&gt;&lt;span style="color: #0000ff"&gt;="80"&lt;/span&gt;&lt;span style="color: #0000ff"&gt;/&amp;gt;&lt;/span&gt;&lt;!--CRLF--&gt;&lt;span style="color: #606060" id="lnum8"&gt;   8:&lt;/span&gt;                 &lt;span style="color: #0000ff"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000"&gt;Trigger&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;!--CRLF--&gt;&lt;span style="color: #606060" id="lnum9"&gt;   9:&lt;/span&gt;             &lt;span style="color: #0000ff"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000"&gt;Style.Triggers&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;!--CRLF--&gt;&lt;span style="color: #606060" id="lnum10"&gt;  10:&lt;/span&gt;         &lt;span style="color: #0000ff"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000"&gt;Style&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;!--CRLF--&gt;&lt;span style="color: #606060" id="lnum11"&gt;  11:&lt;/span&gt;     &lt;span style="color: #0000ff"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000"&gt;Window.Resources&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;!--CRLF--&gt;&lt;span style="color: #606060" id="lnum12"&gt;  12:&lt;/span&gt;     &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;Grid&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;!--CRLF--&gt;&lt;span style="color: #606060" id="lnum13"&gt;  13:&lt;/span&gt;         &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;Button&lt;/span&gt; &lt;span style="color: #ff0000"&gt;x:Name&lt;/span&gt;&lt;span style="color: #0000ff"&gt;="button1"&lt;/span&gt; &lt;span style="color: #ff0000"&gt;Style&lt;/span&gt;&lt;span style="color: #0000ff"&gt;="{StaticResource ButtonStyle}"&lt;/span&gt; &lt;span style="color: #ff0000"&gt;Background&lt;/span&gt;&lt;span style="color: #0000ff"&gt;="{DynamicResource brush}"&lt;/span&gt; &lt;span style="color: #ff0000"&gt;Width&lt;/span&gt;&lt;span style="color: #0000ff"&gt;="20"&lt;/span&gt;&lt;span style="color: #0000ff"&gt;/&amp;gt;&lt;/span&gt;&lt;!--CRLF--&gt;&lt;span style="color: #606060" id="lnum14"&gt;  14:&lt;/span&gt;     &lt;span style="color: #0000ff"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000"&gt;Grid&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;!--CRLF--&gt;&lt;span style="color: #606060" id="lnum15"&gt;  15:&lt;/span&gt; &lt;span style="color: #0000ff"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000"&gt;Window&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;!--CRLF--&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;第4行用Style的Setter设置Width=60，这个优先级是Style；第6行当IsMouseOver为True时设置Width=80，这个优先级是StyleTrigger；第13行使用Style的Button定义Width=20，这个优先级是Local。Local具有最高的优先级，所以即使鼠标移到Button上，第6行的Trigger也会因为优先级不够高而不起作用。如果去掉了第13行中的Width=20，那么鼠标移到Button上时Width会变为80，鼠标移开后会回到第4行的设置的60来。&lt;/p&gt;&lt;h1 style="padding-bottom: 5px; background-color: gray; margin-top: 24px; padding-left: 5px; padding-right: 5px; margin-bottom: 12px; color: white; font-size: 26px; font-weight: normal; padding-top: 5px"&gt;Style &amp;amp; FrameworkElement&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;Style作为一个属性定义在FrameworkElement上，所有继承自FrameworkElement的控件都可以使用Style。FrameworkElement定义了多个Style：Style，ThemeStyle，FocusVisualStyle：&lt;/p&gt;&lt;ol&gt;&lt;li&gt;FocusVisualStyle：是当控件获得键盘焦点时，显示在外面的一个虚线框，这个Style并没有直接作用在对应的FrameworkElement上，而是当控件获得键盘焦点时使用AdornLayer创建了一个新的Control，然后再这个Control上使用FocusVisualStyle，再把它遮盖在对应的FrameworkElement上形成一个虚线框的效果。 &lt;/li&gt;&lt;li&gt;Style：就是我们前面一直设置的Style。 &lt;/li&gt;&lt;li&gt;ThemeStyle：这里引入了一个Theme的概念，具体来谈一下它。&lt;/li&gt;&lt;/ol&gt;&lt;p&gt;Windows定了很多Theme（主题），你可以在控制面板中切换Theme，如图：&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;&lt;a href="http://images.cnblogs.com/cnblogs_com/Zhouyongh/201108/2011080111510875.png"&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="Theme" border="0" alt="Theme" src="http://images.cnblogs.com/cnblogs_com/Zhouyongh/201108/201108011151088057.png" width="580" height="415" /&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;最上面的两排都属于Aero主题，当从Aero主题切换到Windows Classic主题后，任务栏，窗口以及窗口内的控件外观都会发生变化。为了更好的切换主题，WPF引入了ThemeStyle这个概念。当我们使用VS2010的模板生成一个自定义控件（Custom Control）后，会自动添加一个Themes的文件夹以及一个Generic.xaml的文件，如图：&lt;/p&gt;&lt;p&gt;&lt;a href="http://images.cnblogs.com/cnblogs_com/Zhouyongh/201108/201108011151085549.png"&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="generic" border="0" alt="generic" src="http://images.cnblogs.com/cnblogs_com/Zhouyongh/201108/201108011151083041.png" width="209" height="55" /&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;这里的Aero.NormalColor.xaml是手动添加的，先略去不谈，来谈谈控件（Control）的默认样式。&lt;/p&gt;&lt;p&gt;WPF默认提供了很多控件，Button，ListBox，TabControl等等，我们使用这些控件时，是没有指定它的样式（Style）的，WPF为我们提供了默认Style，这个默认Style是与Windows主题相关的。比如我们切换Windows的主题从Aero到Classic，WPF窗口里的控件外观也会发生变化。这些默认的Style是以ResourceDictionary的形式保存在PresentationFramework.Aero.dll，PresentationFramework.Classic.dll等dll中的，这里的命名规则是：程序集名称+Theme名称+.dll。&lt;/p&gt;&lt;p&gt;那么WPF又是如何根据Windows的Theme找到对应的ThemeStyle呢？WPF提出了ThemeInfo这个Attribute来指定Theme信息。ThemeInfo一般定义在Properties/AssemblyInfo.cs中，如：&lt;/p&gt;&lt;div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 100%; padding-right: 4px; font-family: 'Courier New', courier, monospace; direction: ltr; font-size: 8pt; overflow: hidden; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"&gt;&lt;div style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: hidden; padding-top: 0px" id="codeSnippet"&gt;&lt;span style="color: #606060" id="lnum1"&gt;   1:&lt;/span&gt; [assembly: ThemeInfo(&lt;!--CRLF--&gt;&lt;span style="color: #606060" id="lnum2"&gt;   2:&lt;/span&gt;     ResourceDictionaryLocation.SourceAssembly,     &lt;!--CRLF--&gt;&lt;span style="color: #606060" id="lnum3"&gt;   3:&lt;/span&gt;     ResourceDictionaryLocation.SourceAssembly)&lt;!--CRLF--&gt;&lt;span style="color: #606060" id="lnum4"&gt;   4:&lt;/span&gt; )]&lt;!--CRLF--&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;ThemeInfo有两个参数，第一个参数指的是ThemeResource，第二个参数指的是GenericResource，它们的类型是ResourceDictionaryLocation：&lt;/p&gt;&lt;div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 100%; padding-right: 4px; font-family: 'Courier New', courier, monospace; direction: ltr; font-size: 8pt; overflow: hidden; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"&gt;&lt;div style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: hidden; padding-top: 0px" id="codeSnippet"&gt;&lt;span style="color: #606060" id="lnum1"&gt;   1:&lt;/span&gt; &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;enum&lt;/span&gt; ResourceDictionaryLocation&lt;!--CRLF--&gt;&lt;span style="color: #606060" id="lnum2"&gt;   2:&lt;/span&gt; {&lt;!--CRLF--&gt;&lt;span style="color: #606060" id="lnum3"&gt;   3:&lt;/span&gt;     None = 0,&lt;!--CRLF--&gt;&lt;span style="color: #606060" id="lnum4"&gt;   4:&lt;/span&gt;     SourceAssembly = 1,&lt;!--CRLF--&gt;&lt;span style="color: #606060" id="lnum5"&gt;   5:&lt;/span&gt;     ExternalAssembly = 2,&lt;!--CRLF--&gt;&lt;span style="color: #606060" id="lnum6"&gt;   6:&lt;/span&gt; }&lt;!--CRLF--&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;ResourceDictionaryLocation的None指不存在对应的Resource，SourceAssembly指该程序集（Assembly）中存在对应的Resource，ExternalAssembly指对应的Resource保存在外部的程序集（Assembly）中，这个外部程序集的查找规则就是我们前面看到的：程序集名称+Theme名称+.dll。&lt;/p&gt;&lt;p&gt;对于一个控件，无论是系统自带的控件还是我们自定义的控件，WPF启动时都会通过当前Windows系统的Theme查找它对应的ThemeStyle。这个查找规则是：&lt;/p&gt;&lt;ol&gt;&lt;li&gt;先通过控件的类型（Type）找到它对应的程序集（Assembly），然后获取程序集中的ThemeInfo，看看它的ThemeResource和GenericResource在哪里。如果ThemeResource的值不是None，系统会读取到ThemeResource对应的ResourceDictionary，在这个ResourceDictionary中查找是否定义了TargetType={x:Type 控件类型}，如果有，把控件的ThemeStyle指定为这个Style。 &lt;/li&gt;&lt;li&gt;如果第一步的查找失败，那么GenericResource派上用场，Generic这个词表示一般。WPF会查看ThemeInfo的第二个参数GenericResource来查找它的ThemeStyle，查找规则同第一步，如果查找成功，把这个Style指定为控件的ThemeStyle。&lt;/li&gt;&lt;/ol&gt;&lt;p&gt;任意一个控件，如果不显式指定它的Style，并且查不到默认的ThemeStyle，这个控件是没有外观的。为了编程方便，当我们使用VS添加自定义控件时，VS默认帮我们生成了Generic.xaml，如果我们希望自定义的控件也要支持系统的Theme变化，可以在Themes这个文件夹下加入对应的ResourceDictionary，比如上面的Aero.NormalColor.xaml，并且指定程序集ThemeInfo的第一个参数为SourceAssembly，表明该程序集支持系统Theme变化并且对应的资源文件在该程序集中。当然，ResourceDictionary一定要放在Themes文件夹下，因为WPF查找ResourceDictionary时使用的是类似：&lt;/p&gt;&lt;div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 100%; padding-right: 4px; font-family: 'Courier New', courier, monospace; direction: ltr; font-size: 8pt; overflow: hidden; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"&gt;&lt;div style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: hidden; padding-top: 0px" id="codeSnippet"&gt;&lt;span style="color: #606060" id="lnum1"&gt;   1:&lt;/span&gt; &lt;span style="color: #0000ff"&gt;string&lt;/span&gt; relativePackUriForResources = &lt;span style="color: #006080"&gt;"/"&lt;/span&gt; +&lt;!--CRLF--&gt;&lt;span style="color: #606060" id="lnum2"&gt;   2:&lt;/span&gt;         themeAssemblyName.FullName +&lt;!--CRLF--&gt;&lt;span style="color: #606060" id="lnum3"&gt;   3:&lt;/span&gt;         &lt;span style="color: #006080"&gt;";component/themes/"&lt;/span&gt; +&lt;!--CRLF--&gt;&lt;span style="color: #606060" id="lnum4"&gt;   4:&lt;/span&gt;         themeName + &lt;span style="color: #006080"&gt;"."&lt;/span&gt; +&lt;!--CRLF--&gt;&lt;span style="color: #606060" id="lnum5"&gt;   5:&lt;/span&gt;         colorScheme + &lt;span style="color: #006080"&gt;".xaml"&lt;/span&gt;;&lt;!--CRLF--&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;这样的方法。&lt;/p&gt;&lt;h1 style="padding-bottom: 5px; background-color: gray; margin-top: 24px; padding-left: 5px; padding-right: 5px; margin-bottom: 12px; color: white; font-size: 26px; font-weight: normal; padding-top: 5px"&gt;Style &amp;amp; ResourceDictionary&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;前面提到了很多次ResourceDictionary，关于WPF的Resource系统，以后再来细谈。WPF的Resource系统使用ResourceDictionary来储存Resource，ResourceDictionary，顾名思义，也是一个Dictionary，既然是Dictionary，就是按键/值对来存储的。我们最前面在Window的Resource中创建Style时，指定了Style对应的键值（x:Key），后面又用StaticResource来引用这个键值。&lt;/p&gt;&lt;p&gt;如果在ResourceDictionary中添加一个对象Button，不指定它的键值（x:Key），是不能通过编译的。我们前面介绍的隐式（Implicit）Style，只指定了一个TargetType={x:Type&amp;nbsp; 类型}，并没有指定键值，为什么它可以通过编译呢？&lt;/p&gt;&lt;p&gt;对于在ResourceDictionary中添加Style，如果我们没有指定键值（x:Key），WPF会默认帮我们生成键值，这个键值不是一个String，而是一个类型object（具体来说是Type实例），也就是说相当于：&lt;/p&gt;&lt;div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 100%; padding-right: 4px; font-family: 'Courier New', courier, monospace; direction: ltr; font-size: 8pt; overflow: hidden; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"&gt;&lt;div style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: hidden; padding-top: 0px" id="codeSnippet"&gt;&lt;span style="color: #606060" id="lnum1"&gt;   1:&lt;/span&gt; &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;Style&lt;/span&gt; &lt;span style="color: #ff0000"&gt;TargetType&lt;/span&gt;&lt;span style="color: #0000ff"&gt;="{x:Type Button}"&lt;/span&gt; &lt;span style="color: #ff0000"&gt;x:Key&lt;/span&gt;&lt;span style="color: #0000ff"&gt;="{x:Type Button}"&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;!--CRLF--&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;后面的x:Key可以省略掉。&lt;/p&gt;&lt;p&gt;Appliation以及FrameworkElement类都定义了Resources属性，内部都持有一个ResourceDictionary，Resource查找遵循的最基本原则是就近原则，如：&lt;/p&gt;&lt;div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 100%; padding-right: 4px; font-family: 'Courier New', courier, monospace; direction: ltr; font-size: 8pt; overflow: hidden; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"&gt;&lt;div style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: hidden; padding-top: 0px" id="codeSnippet"&gt;&lt;span style="color: #606060" id="lnum1"&gt;   1:&lt;/span&gt; &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;Window&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;!--CRLF--&gt;&lt;span style="color: #606060" id="lnum2"&gt;   2:&lt;/span&gt;     &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;Window.Resources&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;!--CRLF--&gt;&lt;span style="color: #606060" id="lnum3"&gt;   3:&lt;/span&gt;         &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;Style&lt;/span&gt; &lt;span style="color: #ff0000"&gt;TargetType&lt;/span&gt;&lt;span style="color: #0000ff"&gt;="{x:Type Button}"&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;!--CRLF--&gt;&lt;span style="color: #606060" id="lnum4"&gt;   4:&lt;/span&gt;             &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;Setter&lt;/span&gt; &lt;span style="color: #ff0000"&gt;Property&lt;/span&gt;&lt;span style="color: #0000ff"&gt;="Background"&lt;/span&gt; &lt;span style="color: #ff0000"&gt;Value&lt;/span&gt;&lt;span style="color: #0000ff"&gt;="Yellow"&lt;/span&gt;&lt;span style="color: #0000ff"&gt;/&amp;gt;&lt;/span&gt;&lt;!--CRLF--&gt;&lt;span style="color: #606060" id="lnum5"&gt;   5:&lt;/span&gt;         &lt;span style="color: #0000ff"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000"&gt;Style&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;!--CRLF--&gt;&lt;span style="color: #606060" id="lnum6"&gt;   6:&lt;/span&gt;         &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;Style&lt;/span&gt; &lt;span style="color: #ff0000"&gt;TargetType&lt;/span&gt;&lt;span style="color: #0000ff"&gt;="{x:Type ToggleButton}"&lt;/span&gt; &lt;span style="color: #ff0000"&gt;x:Key&lt;/span&gt;&lt;span style="color: #0000ff"&gt;="toggleBtnStyle"&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;!--CRLF--&gt;&lt;span style="color: #606060" id="lnum7"&gt;   7:&lt;/span&gt;             &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;Setter&lt;/span&gt; &lt;span style="color: #ff0000"&gt;Property&lt;/span&gt;&lt;span style="color: #0000ff"&gt;="Background"&lt;/span&gt; &lt;span style="color: #ff0000"&gt;Value&lt;/span&gt;&lt;span style="color: #0000ff"&gt;="Red"&lt;/span&gt;&lt;span style="color: #0000ff"&gt;/&amp;gt;&lt;/span&gt;&lt;!--CRLF--&gt;&lt;span style="color: #606060" id="lnum8"&gt;   8:&lt;/span&gt;         &lt;span style="color: #0000ff"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000"&gt;Style&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;!--CRLF--&gt;&lt;span style="color: #606060" id="lnum9"&gt;   9:&lt;/span&gt;     &lt;span style="color: #0000ff"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000"&gt;Window.Resources&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;!--CRLF--&gt;&lt;span style="color: #606060" id="lnum10"&gt;  10:&lt;/span&gt;     &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;StackPanel&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;!--CRLF--&gt;&lt;span style="color: #606060" id="lnum11"&gt;  11:&lt;/span&gt;         &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;StackPanel.Resources&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;!--CRLF--&gt;&lt;span style="color: #606060" id="lnum12"&gt;  12:&lt;/span&gt;             &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;Style&lt;/span&gt; &lt;span style="color: #ff0000"&gt;TargetType&lt;/span&gt;&lt;span style="color: #0000ff"&gt;="{x:Type Button}"&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;!--CRLF--&gt;&lt;span style="color: #606060" id="lnum13"&gt;  13:&lt;/span&gt;                 &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;Setter&lt;/span&gt; &lt;span style="color: #ff0000"&gt;Property&lt;/span&gt;&lt;span style="color: #0000ff"&gt;="Background"&lt;/span&gt; &lt;span style="color: #ff0000"&gt;Value&lt;/span&gt;&lt;span style="color: #0000ff"&gt;="Blue"&lt;/span&gt;&lt;span style="color: #0000ff"&gt;/&amp;gt;&lt;/span&gt;&lt;!--CRLF--&gt;&lt;span style="color: #606060" id="lnum14"&gt;  14:&lt;/span&gt;             &lt;span style="color: #0000ff"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000"&gt;Style&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;!--CRLF--&gt;&lt;span style="color: #606060" id="lnum15"&gt;  15:&lt;/span&gt;             &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;Style&lt;/span&gt; &lt;span style="color: #ff0000"&gt;TargetType&lt;/span&gt;&lt;span style="color: #0000ff"&gt;="{x:Type ToggleButton}"&lt;/span&gt; &lt;span style="color: #ff0000"&gt;x:Key&lt;/span&gt;&lt;span style="color: #0000ff"&gt;="toggleBtnStyle"&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;!--CRLF--&gt;&lt;span style="color: #606060" id="lnum16"&gt;  16:&lt;/span&gt;                 &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;Setter&lt;/span&gt; &lt;span style="color: #ff0000"&gt;Property&lt;/span&gt;&lt;span style="color: #0000ff"&gt;="Background"&lt;/span&gt; &lt;span style="color: #ff0000"&gt;Value&lt;/span&gt;&lt;span style="color: #0000ff"&gt;="Green"&lt;/span&gt;&lt;span style="color: #0000ff"&gt;/&amp;gt;&lt;/span&gt;&lt;!--CRLF--&gt;&lt;span style="color: #606060" id="lnum17"&gt;  17:&lt;/span&gt;             &lt;span style="color: #0000ff"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000"&gt;Style&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;!--CRLF--&gt;&lt;span style="color: #606060" id="lnum18"&gt;  18:&lt;/span&gt;         &lt;span style="color: #0000ff"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000"&gt;StackPanel.Resources&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;!--CRLF--&gt;&lt;span style="color: #606060" id="lnum19"&gt;  19:&lt;/span&gt;         &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;ToggleButton&lt;/span&gt; &lt;span style="color: #ff0000"&gt;Width&lt;/span&gt;&lt;span style="color: #0000ff"&gt;="80"&lt;/span&gt; &lt;span style="color: #ff0000"&gt;Height&lt;/span&gt;&lt;span style="color: #0000ff"&gt;="20"&lt;/span&gt; &lt;span style="color: #ff0000"&gt;Style&lt;/span&gt;&lt;span style="color: #0000ff"&gt;="{DynamicResource toggleBtnStyle}"&lt;/span&gt;&lt;span style="color: #0000ff"&gt;/&amp;gt;&lt;/span&gt;&lt;!--CRLF--&gt;&lt;span style="color: #606060" id="lnum20"&gt;  20:&lt;/span&gt;         &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;Button&lt;/span&gt; &lt;span style="color: #ff0000"&gt;Width&lt;/span&gt;&lt;span style="color: #0000ff"&gt;="80"&lt;/span&gt; &lt;span style="color: #ff0000"&gt;Height&lt;/span&gt;&lt;span style="color: #0000ff"&gt;="20"&lt;/span&gt;  &lt;span style="color: #ff0000"&gt;Content&lt;/span&gt;&lt;span style="color: #0000ff"&gt;="button2"&lt;/span&gt; &lt;span style="color: #ff0000"&gt;Click&lt;/span&gt;&lt;span style="color: #0000ff"&gt;="Button_Click"&lt;/span&gt;&lt;span style="color: #0000ff"&gt;/&amp;gt;&lt;/span&gt;&lt;!--CRLF--&gt;&lt;span style="color: #606060" id="lnum21"&gt;  21:&lt;/span&gt;     &lt;span style="color: #0000ff"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000"&gt;StackPanel&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;!--CRLF--&gt;&lt;span style="color: #606060" id="lnum22"&gt;  22:&lt;/span&gt; &lt;span style="color: #0000ff"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000"&gt;Window&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;!--CRLF--&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;Window和StackPanel的Resources中都分别定义了toggleBtnStyle以及隐式Style（Button），根据就近原则，StackPanel内部的ToggleButton和Button会应用StackPanel的Resource而不会使用Window的。&lt;/p&gt;&lt;h1 style="padding-bottom: 5px; background-color: gray; margin-top: 24px; padding-left: 5px; padding-right: 5px; margin-bottom: 12px; color: white; font-size: 26px; font-weight: normal; padding-top: 5px"&gt;Style Merge&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;这里要提到本篇的重点也是不被人注意却经常出错的地方，Style的合并（Merge）。&lt;/p&gt;&lt;p&gt;前面提到了很多Style，ThemeStyle，Style，隐式Style。我们提过，Style相当于一个属性值的批处理，那么对于一个属性，只能有一个预设值而不能多个，这些Style在运行时要进行合并，然后作用在FrameworkElement上。&lt;/p&gt;&lt;p&gt;Style的合并，要分两步进行：&lt;/p&gt;&lt;ol&gt;&lt;li&gt;找到所有Style。 &lt;/li&gt;&lt;li&gt;确定Style的优先级，根据优先级来合并Style。&lt;/li&gt;&lt;/ol&gt;&lt;p&gt;以Button来说：&lt;/p&gt;&lt;ol&gt;&lt;li&gt;如果当前Windows的Theme是Aero，启动后会从PresentationFramework.Aero.dll中找到对应的ThemeStyle。 &lt;/li&gt;&lt;li&gt;如果在Button上使用StaticResource或者DynamicResource指定了Style，会通过键值在Resource系统中找到对应的Style。 &lt;/li&gt;&lt;li&gt;如果没有在Button上显式指定Style，会通过Resource系统查找隐式Style（x:Type Button）。 &lt;/li&gt;&lt;li&gt;第二步和第三步是排他的，这两步只能确定一个Style，然后把这个Style和ThemeStyle进行合并（Merge）得到Button最终的效果。&lt;/li&gt;&lt;/ol&gt;&lt;p&gt;先从合并来说，显式或者隐式Style的优先级是高于ThemeStyle的，如果Style和ThemeStyle的Setter中都对同一属性进行了预设，那么会取Style里面的Setter而忽略ThemeStyle。这里比较特殊的是EventSetter，EventSetter使用的是RoutedEvent，如果两个Style的EventSetter对同一个RoutedEvent进行了设置，两个都会注册到RoutedEvent上。&lt;/p&gt;&lt;p&gt;前面看到，显式和隐式Style是排他的，两者只能取一，在实际项目中，在全局定义好Button的基本样式，然后具体使用上再根据基本样式做一些特殊处理，这种需求是很常见的。为了解决这种需求，Style提出了BasedOn属性，来表示继承关系，如：&lt;/p&gt;&lt;div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 100%; padding-right: 4px; font-family: 'Courier New', courier, monospace; direction: ltr; font-size: 8pt; overflow: hidden; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"&gt;&lt;div style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: hidden; padding-top: 0px" id="codeSnippet"&gt;&lt;span style="color: #606060" id="lnum1"&gt;   1:&lt;/span&gt; &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;Window&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;!--CRLF--&gt;&lt;span style="color: #606060" id="lnum2"&gt;   2:&lt;/span&gt;     &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;Window.Resources&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;!--CRLF--&gt;&lt;span style="color: #606060" id="lnum3"&gt;   3:&lt;/span&gt;         &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;Style&lt;/span&gt; &lt;span style="color: #ff0000"&gt;TargetType&lt;/span&gt;&lt;span style="color: #0000ff"&gt;="{x:Type Button}"&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;!--CRLF--&gt;&lt;span style="color: #606060" id="lnum4"&gt;   4:&lt;/span&gt;             &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;Setter&lt;/span&gt; &lt;span style="color: #ff0000"&gt;Property&lt;/span&gt;&lt;span style="color: #0000ff"&gt;="Width"&lt;/span&gt; &lt;span style="color: #ff0000"&gt;Value&lt;/span&gt;&lt;span style="color: #0000ff"&gt;="80"&lt;/span&gt;&lt;span style="color: #0000ff"&gt;/&amp;gt;&lt;/span&gt;&lt;!--CRLF--&gt;&lt;span style="color: #606060" id="lnum5"&gt;   5:&lt;/span&gt;             &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;Setter&lt;/span&gt; &lt;span style="color: #ff0000"&gt;Property&lt;/span&gt;&lt;span style="color: #0000ff"&gt;="Height"&lt;/span&gt; &lt;span style="color: #ff0000"&gt;Value&lt;/span&gt;&lt;span style="color: #0000ff"&gt;="20"&lt;/span&gt;&lt;span style="color: #0000ff"&gt;/&amp;gt;&lt;/span&gt;&lt;!--CRLF--&gt;&lt;span style="color: #606060" id="lnum6"&gt;   6:&lt;/span&gt;             &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;EventSetter&lt;/span&gt; &lt;span style="color: #ff0000"&gt;Event&lt;/span&gt;&lt;span style="color: #0000ff"&gt;="Click"&lt;/span&gt; &lt;span style="color: #ff0000"&gt;Handler&lt;/span&gt;&lt;span style="color: #0000ff"&gt;="btnBase_Click"&lt;/span&gt;&lt;span style="color: #0000ff"&gt;/&amp;gt;&lt;/span&gt;&lt;!--CRLF--&gt;&lt;span style="color: #606060" id="lnum7"&gt;   7:&lt;/span&gt;         &lt;span style="color: #0000ff"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000"&gt;Style&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;!--CRLF--&gt;&lt;span style="color: #606060" id="lnum8"&gt;   8:&lt;/span&gt;         &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;Style&lt;/span&gt; &lt;span style="color: #ff0000"&gt;TargetType&lt;/span&gt;&lt;span style="color: #0000ff"&gt;="{x:Type ButtonBase}"&lt;/span&gt; &lt;span style="color: #ff0000"&gt;x:Key&lt;/span&gt;&lt;span style="color: #0000ff"&gt;="toggleBtnStyle"&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;!--CRLF--&gt;&lt;span style="color: #606060" id="lnum9"&gt;   9:&lt;/span&gt;             &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;Setter&lt;/span&gt; &lt;span style="color: #ff0000"&gt;Property&lt;/span&gt;&lt;span style="color: #0000ff"&gt;="Width"&lt;/span&gt; &lt;span style="color: #ff0000"&gt;Value&lt;/span&gt;&lt;span style="color: #0000ff"&gt;="80"&lt;/span&gt;&lt;span style="color: #0000ff"&gt;/&amp;gt;&lt;/span&gt;&lt;!--CRLF--&gt;&lt;span style="color: #606060" id="lnum10"&gt;  10:&lt;/span&gt;             &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;Setter&lt;/span&gt; &lt;span style="color: #ff0000"&gt;Property&lt;/span&gt;&lt;span style="color: #0000ff"&gt;="Height"&lt;/span&gt; &lt;span style="color: #ff0000"&gt;Value&lt;/span&gt;&lt;span style="color: #0000ff"&gt;="20"&lt;/span&gt;&lt;span style="color: #0000ff"&gt;/&amp;gt;&lt;/span&gt;&lt;!--CRLF--&gt;&lt;span style="color: #606060" id="lnum11"&gt;  11:&lt;/span&gt;             &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;Setter&lt;/span&gt; &lt;span style="color: #ff0000"&gt;Property&lt;/span&gt;&lt;span style="color: #0000ff"&gt;="Background"&lt;/span&gt; &lt;span style="color: #ff0000"&gt;Value&lt;/span&gt;&lt;span style="color: #0000ff"&gt;="Red"&lt;/span&gt;&lt;span style="color: #0000ff"&gt;/&amp;gt;&lt;/span&gt;&lt;!--CRLF--&gt;&lt;span style="color: #606060" id="lnum12"&gt;  12:&lt;/span&gt;         &lt;span style="color: #0000ff"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000"&gt;Style&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;!--CRLF--&gt;&lt;span style="color: #606060" id="lnum13"&gt;  13:&lt;/span&gt;     &lt;span style="color: #0000ff"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000"&gt;Window.Resources&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;!--CRLF--&gt;&lt;span style="color: #606060" id="lnum14"&gt;  14:&lt;/span&gt;     &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;StackPanel&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;!--CRLF--&gt;&lt;span style="color: #606060" id="lnum15"&gt;  15:&lt;/span&gt;         &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;StackPanel.Resources&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;!--CRLF--&gt;&lt;span style="color: #606060" id="lnum16"&gt;  16:&lt;/span&gt;             &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;Style&lt;/span&gt; &lt;span style="color: #ff0000"&gt;TargetType&lt;/span&gt;&lt;span style="color: #0000ff"&gt;="{x:Type Button}"&lt;/span&gt; &lt;span style="color: #ff0000"&gt;BasedOn&lt;/span&gt;&lt;span style="color: #0000ff"&gt;="{StaticResource {x:Type Button}}"&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;!--CRLF--&gt;&lt;span style="color: #606060" id="lnum17"&gt;  17:&lt;/span&gt;                 &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;Setter&lt;/span&gt; &lt;span style="color: #ff0000"&gt;Property&lt;/span&gt;&lt;span style="color: #0000ff"&gt;="Background"&lt;/span&gt; &lt;span style="color: #ff0000"&gt;Value&lt;/span&gt;&lt;span style="color: #0000ff"&gt;="Blue"&lt;/span&gt;&lt;span style="color: #0000ff"&gt;/&amp;gt;&lt;/span&gt;&lt;!--CRLF--&gt;&lt;span style="color: #606060" id="lnum18"&gt;  18:&lt;/span&gt;                 &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;EventSetter&lt;/span&gt; &lt;span style="color: #ff0000"&gt;Event&lt;/span&gt;&lt;span style="color: #0000ff"&gt;="Click"&lt;/span&gt; &lt;span style="color: #ff0000"&gt;Handler&lt;/span&gt;&lt;span style="color: #0000ff"&gt;="btn_Click"&lt;/span&gt;&lt;span style="color: #0000ff"&gt;/&amp;gt;&lt;/span&gt;&lt;!--CRLF--&gt;&lt;span style="color: #606060" id="lnum19"&gt;  19:&lt;/span&gt;             &lt;span style="color: #0000ff"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000"&gt;Style&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;!--CRLF--&gt;&lt;span style="color: #606060" id="lnum20"&gt;  20:&lt;/span&gt;             &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;Style&lt;/span&gt; &lt;span style="color: #ff0000"&gt;TargetType&lt;/span&gt;&lt;span style="color: #0000ff"&gt;="{x:Type ToggleButton}"&lt;/span&gt; &lt;span style="color: #ff0000"&gt;x:Key&lt;/span&gt;&lt;span style="color: #0000ff"&gt;="toggleBtnStyle"&lt;/span&gt; &lt;span style="color: #ff0000"&gt;BasedOn&lt;/span&gt;&lt;span style="color: #0000ff"&gt;="{StaticResource toggleBtnStyle}"&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;!--CRLF--&gt;&lt;span style="color: #606060" id="lnum21"&gt;  21:&lt;/span&gt;                 &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;Setter&lt;/span&gt; &lt;span style="color: #ff0000"&gt;Property&lt;/span&gt;&lt;span style="color: #0000ff"&gt;="Background"&lt;/span&gt; &lt;span style="color: #ff0000"&gt;Value&lt;/span&gt;&lt;span style="color: #0000ff"&gt;="Green"&lt;/span&gt;&lt;span style="color: #0000ff"&gt;/&amp;gt;&lt;/span&gt;&lt;!--CRLF--&gt;&lt;span style="color: #606060" id="lnum22"&gt;  22:&lt;/span&gt;             &lt;span style="color: #0000ff"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000"&gt;Style&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;!--CRLF--&gt;&lt;span style="color: #606060" id="lnum23"&gt;  23:&lt;/span&gt;         &lt;span style="color: #0000ff"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000"&gt;StackPanel.Resources&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;!--CRLF--&gt;&lt;span style="color: #606060" id="lnum24"&gt;  24:&lt;/span&gt;         &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;ToggleButton&lt;/span&gt; &lt;span style="color: #ff0000"&gt;Style&lt;/span&gt;&lt;span style="color: #0000ff"&gt;="{DynamicResource toggleBtnStyle}"&lt;/span&gt;&lt;span style="color: #0000ff"&gt;/&amp;gt;&lt;/span&gt;&lt;!--CRLF--&gt;&lt;span style="color: #606060" id="lnum25"&gt;  25:&lt;/span&gt;         &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;Button&lt;/span&gt; &lt;span style="color: #ff0000"&gt;Content&lt;/span&gt;&lt;span style="color: #0000ff"&gt;="button2"&lt;/span&gt;&lt;span style="color: #0000ff"&gt;/&amp;gt;&lt;/span&gt;&lt;!--CRLF--&gt;&lt;span style="color: #606060" id="lnum26"&gt;  26:&lt;/span&gt;     &lt;span style="color: #0000ff"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000"&gt;StackPanel&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;!--CRLF--&gt;&lt;span style="color: #606060" id="lnum27"&gt;  27:&lt;/span&gt; &lt;span style="color: #0000ff"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000"&gt;Window&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;!--CRLF--&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;为了更清晰的解释，给出了一个不太常见的例子。第16行创建了一个隐式Style（Button），它的BasedOn属性仍然是隐式Style（Button），Resource系统会向上查找找到Window的Resorces中的隐式Style（Button），然后把两者合并。对于同一个ResourceDictionary，是不允许有重复键值的，StackPanel和Window各有各自的ResourceDictionary，他们的键值不受干扰，查找时会通过就近原则来找到优先级最高的Resource。第20行ToggleButton的例子和Button是一样的，只是它查找到的第8行toggleBtnStyle的TargetStyle是ButtonBase，ButtonBase是ToggleButton的基类，BasedOn属性也可以作用。&lt;/p&gt;&lt;p&gt;WPF的Style机制是一个密封（Seal）机制，它的书写方式很灵活，可以支持合并等，当最后合并后，Style就被密封（Seal），内部的Setter等不允许再被修改。这种密封的设计有它的道理，但在Style的动态性上就稍显不足。&lt;/p&gt;&lt;p&gt;以自定义控件为例，自定义一个Button，名字叫MyButton，它继承自Button，在自定义控件中，经常可以看到这样的代码：&lt;/p&gt;&lt;div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 100%; padding-right: 4px; font-family: 'Courier New', courier, monospace; direction: ltr; font-size: 8pt; overflow: hidden; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"&gt;&lt;div style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: hidden; padding-top: 0px" id="codeSnippet"&gt;&lt;span style="color: #606060" id="lnum1"&gt;   1:&lt;/span&gt; &lt;span style="color: #0000ff"&gt;static&lt;/span&gt; MyButton()&lt;!--CRLF--&gt;&lt;span style="color: #606060" id="lnum2"&gt;   2:&lt;/span&gt; {&lt;!--CRLF--&gt;&lt;span style="color: #606060" id="lnum3"&gt;   3:&lt;/span&gt;     DefaultStyleKeyProperty.OverrideMetadata(&lt;span style="color: #0000ff"&gt;typeof&lt;/span&gt;(MyButton), &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; FrameworkPropertyMetadata(&lt;span style="color: #0000ff"&gt;typeof&lt;/span&gt;(MyButton)));&lt;!--CRLF--&gt;&lt;span style="color: #606060" id="lnum4"&gt;   4:&lt;/span&gt; }&lt;!--CRLF--&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;这里出现了DefaultStyle，这个是WPF对ThemeStyle的另一个说法，ThemeStyle就是用来确定默认的Style的，后来包括BaseValueSource中也使用了DefaultStyle来表示ThemeStyle。在MyButton的静态函数中重载DefaultStyleKeyProperty内部Metadata的含义是告诉WPF系统，查找MyButton的ThemeStyle使用的键值从{x:Type Button}被改成了{x:Type MyButton}。&lt;/p&gt;&lt;p&gt;如果像上述代码一样修改了DefaultStyleKeyProperty，那么需要我们在Themes/Generic.xaml中定义好MyButton的默认（Theme）Style，否则MyButton是没有外观的，因为查找ThemeStyle的键值已经被修改，PresentationFramework.Aero.dll等dll中是没有定义{x:Type MyButton}的。&lt;/p&gt;&lt;p&gt;前面是关于ThemeStyle的用法，那么回到隐式Style上来，如果我们在Application的Resources中定义了Button的隐式Style（TargetType={x:Type Button}），即使没有显式设置MyButton的Style，所有的MyButton控件也不会使用这个隐式Style的。需要你在Application的Resources中，在定义Button隐式Style的下面定义&lt;/p&gt;&lt;div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 100%; padding-right: 4px; font-family: 'Courier New', courier, monospace; direction: ltr; font-size: 8pt; overflow: hidden; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"&gt;&lt;div style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: hidden; padding-top: 0px" id="codeSnippet"&gt;&lt;span style="color: #606060" id="lnum1"&gt;   1:&lt;/span&gt; &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;Style&lt;/span&gt; &lt;span style="color: #ff0000"&gt;TargetType&lt;/span&gt;&lt;span style="color: #0000ff"&gt;="{x:Type local:MyButton}"&lt;/span&gt; &lt;span style="color: #ff0000"&gt;BasedOn&lt;/span&gt;&lt;span style="color: #0000ff"&gt;="{StaticResource {x:Type Button}}"&lt;/span&gt;&lt;span style="color: #0000ff"&gt;/&amp;gt;&lt;/span&gt;&lt;!--CRLF--&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;这里就回到Style的合并（Merge）上来了，Style的Merge是很基本（很傻）的合并（Merge），它不具备Auto性。具体来说，就是：&lt;/p&gt;&lt;ol&gt;&lt;li&gt;基类控件的隐式Style不会作用到派生类控件上。 &lt;/li&gt;&lt;li&gt;像前面在Window和StackPanel中分别定义了隐式Style（Button），这两个隐式Style不会智能合并后再作用到Button上，而是通过就近原则只选其一。 &lt;/li&gt;&lt;li&gt;Style的BasedOn属性只支持StaticResource方式引用，因为Style继承自DispatcherObject而不是DependencyObject，DynamicResource只支持DP。&lt;/li&gt;&lt;/ol&gt;&lt;p&gt;这些问题都需要通过Style的BasedOn来解决，因为BasedOn用的是静态引用（StaticResource），当隐式Style发生变化时就有麻烦了。&lt;/p&gt;&lt;h1 style="padding-bottom: 5px; background-color: gray; margin-top: 24px; padding-left: 5px; padding-right: 5px; margin-bottom: 12px; color: white; font-size: 26px; font-weight: normal; padding-top: 5px"&gt;换肤&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;UI程序的换肤是很炫的玩意，换肤分两种：1，更换整个控件的Style；2，更换Style中的颜色画刷（Brush）。后者的实现很简单，定义好颜色画刷的资源文件（ResourceDictionary），使用画刷的时候使用DynamicResource绑定，换肤的时候替换画刷的资源文件就可以了。&lt;/p&gt;&lt;p&gt;很多公司都有自己皮肤库，这些皮肤库一般都是隐式的Style，定义了所有控件的隐式Style，使用时把这个皮肤资源Merge到Application的Resources中。换肤时把旧的皮肤资源从Application的Resources中删除，替换成新的皮肤资源ResourceDictionary。&lt;/p&gt;&lt;p&gt;这种做法很好理解，但是碰到Style的BasedOn属性就不起作用了，BasedOn属性使用是StaticResource，是静态的一次性的。新的皮肤库被添加到Application资源文件后，如果在Application的资源文件中已经定义过&amp;lt;Style TargetType=&amp;#8220;{x:Type Button}&amp;#8221; BasedOn=&amp;#8220;{StaticResource {x:Type Button}}&amp;#8221;/&amp;gt;这样隐式的Style，控件是不会更新皮肤的。如果有这方面的需求，需要手动合并（Merge）Style来解决问题，类似：&lt;/p&gt;&lt;div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 100%; padding-right: 4px; font-family: 'Courier New', courier, monospace; direction: ltr; font-size: 8pt; overflow: hidden; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"&gt;&lt;div style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: hidden; padding-top: 0px" id="codeSnippet"&gt;&lt;span style="color: #606060" id="lnum1"&gt;   1:&lt;/span&gt; &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;static&lt;/span&gt; &lt;span style="color: #0000ff"&gt;void&lt;/span&gt; Merge(&lt;span style="color: #0000ff"&gt;this&lt;/span&gt; Style style, Style otherStyle)&lt;!--CRLF--&gt;&lt;span style="color: #606060" id="lnum2"&gt;   2:&lt;/span&gt; {&lt;!--CRLF--&gt;&lt;span style="color: #606060" id="lnum3"&gt;   3:&lt;/span&gt;     &lt;span style="color: #0000ff"&gt;foreach&lt;/span&gt; (SetterBase currentSetter &lt;span style="color: #0000ff"&gt;in&lt;/span&gt; otherStyle.Setters)&lt;!--CRLF--&gt;&lt;span style="color: #606060" id="lnum4"&gt;   4:&lt;/span&gt;     {&lt;!--CRLF--&gt;&lt;span style="color: #606060" id="lnum5"&gt;   5:&lt;/span&gt;         style.Setters.Add(currentSetter);&lt;!--CRLF--&gt;&lt;span style="color: #606060" id="lnum6"&gt;   6:&lt;/span&gt;     }&lt;!--CRLF--&gt;&lt;span style="color: #606060" id="lnum7"&gt;   7:&lt;/span&gt;&amp;nbsp; &lt;!--CRLF--&gt;&lt;span style="color: #606060" id="lnum8"&gt;   8:&lt;/span&gt;     &lt;span style="color: #0000ff"&gt;foreach&lt;/span&gt; (TriggerBase currentTrigger &lt;span style="color: #0000ff"&gt;in&lt;/span&gt; otherStyle.Triggers)&lt;!--CRLF--&gt;&lt;span style="color: #606060" id="lnum9"&gt;   9:&lt;/span&gt;     {&lt;!--CRLF--&gt;&lt;span style="color: #606060" id="lnum10"&gt;  10:&lt;/span&gt;         style.Triggers.Add(currentTrigger);&lt;!--CRLF--&gt;&lt;span style="color: #606060" id="lnum11"&gt;  11:&lt;/span&gt;     }&lt;!--CRLF--&gt;&lt;span style="color: #606060" id="lnum12"&gt;  12:&lt;/span&gt;&amp;nbsp; &lt;!--CRLF--&gt;&lt;span style="color: #606060" id="lnum13"&gt;  13:&lt;/span&gt;     &lt;span style="color: #0000ff"&gt;foreach&lt;/span&gt; (&lt;span style="color: #0000ff"&gt;object&lt;/span&gt; key &lt;span style="color: #0000ff"&gt;in&lt;/span&gt; otherStyle.Resources.Keys)&lt;!--CRLF--&gt;&lt;span style="color: #606060" id="lnum14"&gt;  14:&lt;/span&gt;     {&lt;!--CRLF--&gt;&lt;span style="color: #606060" id="lnum15"&gt;  15:&lt;/span&gt;         style.Resources[key] = otherStyle.Resources[key];&lt;!--CRLF--&gt;&lt;span style="color: #606060" id="lnum16"&gt;  16:&lt;/span&gt;     }&lt;!--CRLF--&gt;&lt;span style="color: #606060" id="lnum17"&gt;  17:&lt;/span&gt; }&lt;!--CRLF--&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;这里还需要加上一些条件判断，以及决定是否要递归合并otherStyle的BasedOn，回到前面，程序需要使用DynamicResource来监听Application资源中隐式Style的变化，用一个附加属性来解决：&lt;/p&gt;&lt;div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 100%; padding-right: 4px; font-family: 'Courier New', courier, monospace; direction: ltr; font-size: 8pt; overflow: hidden; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"&gt;&lt;div style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: hidden; padding-top: 0px" id="codeSnippet"&gt;&lt;span style="color: #606060" id="lnum1"&gt;   1:&lt;/span&gt; &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;static&lt;/span&gt; &lt;span style="color: #0000ff"&gt;readonly&lt;/span&gt; DependencyProperty AutoMergeStyleProperty =&lt;!--CRLF--&gt;&lt;span style="color: #606060" id="lnum2"&gt;   2:&lt;/span&gt;     DependencyProperty.RegisterAttached(&lt;span style="color: #006080"&gt;"AutoMergeStyle"&lt;/span&gt;, &lt;span style="color: #0000ff"&gt;typeof&lt;/span&gt;(Type), &lt;span style="color: #0000ff"&gt;typeof&lt;/span&gt;(Behavior),&lt;!--CRLF--&gt;&lt;span style="color: #606060" id="lnum3"&gt;   3:&lt;/span&gt;         &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; FrameworkPropertyMetadata((Type)&lt;span style="color: #0000ff"&gt;null&lt;/span&gt;,&lt;!--CRLF--&gt;&lt;span style="color: #606060" id="lnum4"&gt;   4:&lt;/span&gt;             &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; PropertyChangedCallback(OnAutoMergeStyleChanged)));&lt;!--CRLF--&gt;&lt;span style="color: #606060" id="lnum5"&gt;   5:&lt;/span&gt;&amp;nbsp; &lt;!--CRLF--&gt;&lt;span style="color: #606060" id="lnum6"&gt;   6:&lt;/span&gt; &lt;span style="color: #0000ff"&gt;private&lt;/span&gt; &lt;span style="color: #0000ff"&gt;static&lt;/span&gt; &lt;span style="color: #0000ff"&gt;void&lt;/span&gt; OnAutoMergeStyleChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)&lt;!--CRLF--&gt;&lt;span style="color: #606060" id="lnum7"&gt;   7:&lt;/span&gt; {&lt;!--CRLF--&gt;&lt;span style="color: #606060" id="lnum8"&gt;   8:&lt;/span&gt;     &lt;span style="color: #0000ff"&gt;if&lt;/span&gt; (e.OldValue == e.NewValue)&lt;!--CRLF--&gt;&lt;span style="color: #606060" id="lnum9"&gt;   9:&lt;/span&gt;     {&lt;!--CRLF--&gt;&lt;span style="color: #606060" id="lnum10"&gt;  10:&lt;/span&gt;         &lt;span style="color: #0000ff"&gt;return&lt;/span&gt;;&lt;!--CRLF--&gt;&lt;span style="color: #606060" id="lnum11"&gt;  11:&lt;/span&gt;     }&lt;!--CRLF--&gt;&lt;span style="color: #606060" id="lnum12"&gt;  12:&lt;/span&gt;&amp;nbsp; &lt;!--CRLF--&gt;&lt;span style="color: #606060" id="lnum13"&gt;  13:&lt;/span&gt;     FrameworkElement control = d &lt;span style="color: #0000ff"&gt;as&lt;/span&gt; FrameworkElement;&lt;!--CRLF--&gt;&lt;span style="color: #606060" id="lnum14"&gt;  14:&lt;/span&gt;     &lt;span style="color: #0000ff"&gt;if&lt;/span&gt; (control == &lt;span style="color: #0000ff"&gt;null&lt;/span&gt;)&lt;!--CRLF--&gt;&lt;span style="color: #606060" id="lnum15"&gt;  15:&lt;/span&gt;     {&lt;!--CRLF--&gt;&lt;span style="color: #606060" id="lnum16"&gt;  16:&lt;/span&gt;         &lt;span style="color: #0000ff"&gt;throw&lt;/span&gt; &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; NotSupportedException(&lt;span style="color: #006080"&gt;"AutoMergeStyle can only used in FrameworkElement"&lt;/span&gt;);&lt;!--CRLF--&gt;&lt;span style="color: #606060" id="lnum17"&gt;  17:&lt;/span&gt;     }&lt;!--CRLF--&gt;&lt;span style="color: #606060" id="lnum18"&gt;  18:&lt;/span&gt;&amp;nbsp; &lt;!--CRLF--&gt;&lt;span style="color: #606060" id="lnum19"&gt;  19:&lt;/span&gt;     Type type = e.NewValue &lt;span style="color: #0000ff"&gt;as&lt;/span&gt; Type;&lt;!--CRLF--&gt;&lt;span style="color: #606060" id="lnum20"&gt;  20:&lt;/span&gt;     &lt;span style="color: #0000ff"&gt;if&lt;/span&gt; (type != &lt;span style="color: #0000ff"&gt;null&lt;/span&gt;)&lt;!--CRLF--&gt;&lt;span style="color: #606060" id="lnum21"&gt;  21:&lt;/span&gt;     {&lt;!--CRLF--&gt;&lt;span style="color: #606060" id="lnum22"&gt;  22:&lt;/span&gt;         control.SetResourceReference(Behavior.BaseOnStyleProperty, type);&lt;!--CRLF--&gt;&lt;span style="color: #606060" id="lnum23"&gt;  23:&lt;/span&gt;     }&lt;!--CRLF--&gt;&lt;span style="color: #606060" id="lnum24"&gt;  24:&lt;/span&gt;     &lt;span style="color: #0000ff"&gt;else&lt;/span&gt;&lt;!--CRLF--&gt;&lt;span style="color: #606060" id="lnum25"&gt;  25:&lt;/span&gt;     {&lt;!--CRLF--&gt;&lt;span style="color: #606060" id="lnum26"&gt;  26:&lt;/span&gt;         control.ClearValue(Behavior.BaseOnStyleProperty);&lt;!--CRLF--&gt;&lt;span style="color: #606060" id="lnum27"&gt;  27:&lt;/span&gt;     }&lt;!--CRLF--&gt;&lt;span style="color: #606060" id="lnum28"&gt;  28:&lt;/span&gt; }&lt;!--CRLF--&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;SetResourceReference是XAML中DynamicResource的代码表示，相当于Behavior.BaseOnStyle={DynamicResource type}。对控件使用SetResourceReference，监听的键值是type，监听的属性是一个我们自定义的附加属性BaseOnStyleProperty。当换肤替换Application的资源文件时，BaseOnStyle属性被更新，在BaseOnStyleProperty的Changed事件中可以读取控件的Style属性和新的ThemeStyle，调用Merge方法Merge两者然后再设置到控件的Style属性上。&lt;/p&gt;&lt;h1 style="padding-bottom: 5px; background-color: gray; margin-top: 24px; padding-left: 5px; padding-right: 5px; margin-bottom: 12px; color: white; font-size: 26px; font-weight: normal; padding-top: 5px"&gt;总结&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;WPF中Style的设计中规中矩，把UI对象样式和结构分离是它的最初想法，其中也加入了Trigger等一些好的设计，但在使用中还是会出现一些问题，它本身也不是那么智能完美。希望朋友们都能从内到外的看待Style，更好的玩转它。&lt;/p&gt;&lt;h1 style="padding-bottom: 5px; background-color: gray; margin-top: 24px; padding-left: 5px; padding-right: 5px; margin-bottom: 12px; color: white; font-size: 26px; font-weight: normal; padding-top: 5px"&gt;闲话&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;这个深入WPF系列也写了好几篇了，比起用嘴上白话一通，写文章需要更多的耐心和细致。讲解有很多境界：把简单的东西讲复杂；把复杂的东西讲复杂；把复杂的东西讲简单；把复杂的东西讲简单，而且还有诗情哲理。我达不到那么高的境界，希望能做到直接不回避的把技术主线讲清楚，也希望能更多的听到朋友们的反馈，我会继续补充，争取把这个系列写好。&lt;/p&gt;&lt;p&gt;谢谢支持，谢谢您顶一下。　^_^&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;div&gt;&lt;span style="line-height: 25px; color: #333333"&gt;&lt;span style="line-height: 25px; background-color: #ffffff; font-family: georgia; color: #333333"&gt;&lt;span style="padding-bottom: 0px; line-height: 21px; margin: 0px; padding-left: 0px; padding-right: 0px; font-family: 宋体; color: black; font-size: 9pt; padding-top: 0px"&gt;作者：&lt;/span&gt;&lt;span style="padding-bottom: 0px; line-height: 21px; margin: 0px; padding-left: 0px; padding-right: 0px; font-family: verdana, sans-serif; color: black; font-size: 9pt; padding-top: 0px"&gt;&lt;a style="border-bottom: 1px dashed; padding-bottom: 0px; margin: 0px; outline-style: none; outline-color: ; padding-left: 0px; padding-right: 0px; color: #3d81ee; text-decoration: none; padding-top: 0px" href="http://www.cnblogs.com/Zhouyongh" target="_blank"&gt;&lt;span style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; font-family: 宋体; color: #ff6600; text-decoration: none; padding-top: 0px"&gt;周永恒&lt;/span&gt;&lt;/a&gt; &lt;br style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px" /&gt;&lt;/span&gt;&lt;span style="padding-bottom: 0px; line-height: 21px; margin: 0px; padding-left: 0px; padding-right: 0px; font-family: 宋体; color: black; font-size: 9pt; padding-top: 0px"&gt;出处：&lt;/span&gt;&lt;span style="padding-bottom: 0px; line-height: 21px; margin: 0px; padding-left: 0px; padding-right: 0px; font-family: verdana, sans-serif; color: black; font-size: 9pt; padding-top: 0px"&gt;&lt;a style="border-bottom: 1px dashed; padding-bottom: 0px; margin: 0px; outline-style: none; outline-color: ; padding-left: 0px; padding-right: 0px; color: #3d81ee; text-decoration: none; padding-top: 0px" href="http://www.cnblogs.com/Zhouyongh" target="_blank"&gt;&lt;span style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; color: #ff6600; text-decoration: none; padding-top: 0px"&gt;http://www.cnblogs.com/Zhouyongh&lt;/span&gt;&lt;/a&gt; &lt;br style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px" /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;p&gt;&lt;span style="line-height: 25px; font-family: 宋体; color: #333333; font-size: 12px" class="Apple-style-span"&gt;本文版权归作者和博客园共有，欢迎转载，但未经作者同意必须保留此段声明，且在文章页面明显位置给出原文连接，否则保留追究法律责任的权利。&lt;/span&gt;&lt;/p&gt;&lt;img src="http://www.cnblogs.com/Zhouyongh/aggbug/2123610.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/Zhouyongh/archive/2011/08/01/2123610.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/Zhouyongh/archive/2011/07/20/2111716.html</id><title type="text">解析Caliburn.Micro（三）</title><summary type="text">书接前文，前篇文章简略了介绍了一下Caliburn.Micro（简称CM）的Action，这篇文章继续讨论CM的下一个Feature：Convention。</summary><published>2011-07-20T07:43:00Z</published><updated>2011-07-20T07:43:00Z</updated><author><name>周永恒</name><uri>http://www.cnblogs.com/Zhouyongh/</uri></author><link rel="alternate" href="http://www.cnblogs.com/Zhouyongh/archive/2011/07/20/2111716.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/Zhouyongh/archive/2011/07/20/2111716.html"/><content type="html">&lt;p&gt;书接&lt;a href="http://www.cnblogs.com/Zhouyongh/archive/2011/04/22/2018989.html"&gt;前文&lt;/a&gt;，前篇文章简略了介绍了一下Caliburn.Micro（简称CM）的Action，这篇文章继续讨论CM的下一个Feature：Convention。&lt;/p&gt;  &lt;h1 style="padding-bottom: 5px; background-color: gray; margin-top: 24px; padding-left: 5px; padding-right: 5px; margin-bottom: 12px; color: white; font-size: 26px; font-weight: normal; padding-top: 5px"&gt;什么是Convention&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;Convention，翻译过来叫公约、协定。公约，一般指行为规范，达成共识的多方共同遵守的一个约定。在CM中，Convention主要用来做配对，匹配。这个配对，主要是指View和ViewModel之间的配对，前篇文章已经提过，CM是基于&lt;a href="http://en.wikipedia.org/wiki/Model_View_ViewModel"&gt;MVVM&lt;/a&gt;模式的，MVVM（Model-View-ViewModel）中，Model是用来保存数据的，相对来说它比较固定，View和ViewModel之间的关系有一些变化，简单的说一说。&lt;/p&gt;  &lt;h1 style="padding-bottom: 5px; background-color: gray; margin-top: 24px; padding-left: 5px; padding-right: 5px; margin-bottom: 12px; color: white; font-size: 26px; font-weight: normal; padding-top: 5px"&gt;View-First or ViewModel-First&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;MVVM中，ViewModel的作用是储存View的状态，封装Model的数据。ViewModel是PresentationModel模式发展而来的，ViewModel中并不会储存所有的View的状态，它只存储可能被修改的View的状态。WPF的出现，主要提供了两个技术，让ViewModel的出现成为了可能：&lt;/p&gt;  &lt;ol&gt;   &lt;li&gt;数据绑定，WPF提供了数据绑定，View绑定到ViewModel，使用ViewModel作为它的DataContext。当ViewModel中存储的View状态发生改变的时候，View会自动刷新状态。 &lt;/li&gt;    &lt;li&gt;Command，WPF提供了ICommand，当用户操作View时，会通过Command把操作传递给ViewModel。 &lt;/li&gt; &lt;/ol&gt;  &lt;p&gt;View的两大功能，显示数据和操作数据，分别被抽象出来，它的状态也被保存在ViewModel中，由于使用了数据绑定，View通过DataContext来关联ViewModel，两者之间是松耦合的，这也是MVVM模式的精彩之处。那么回到本篇文章要讨论的点上，View和ViewModel如何关联？谁来找到谁？View-First or ViewModel-First?&lt;/p&gt;  &lt;h1 style="padding-bottom: 5px; background-color: gray; margin-top: 24px; padding-left: 5px; padding-right: 5px; margin-bottom: 12px; color: white; font-size: 26px; font-weight: normal; padding-top: 5px"&gt;ViewModel-First&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;通常情况下，都会推荐大家ViewModel-First。设计时先设计好ViewModel，再通过数据模板（DataTemplate）来生成对应的View。这样做的好处是可以随时替换View，单元测试时可以Mock一个View测试。CM框架提供了ViewLocator来通过ViewModel定位对应的View，它的方法如下：&lt;/p&gt;  &lt;div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 100%; padding-right: 4px; font-family: 'Courier New', courier, monospace; direction: ltr; font-size: 8pt; overflow: hidden; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"&gt;   &lt;div style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: hidden; padding-top: 0px" id="codeSnippet"&gt;     &lt;span style="color: #606060" id="lnum1"&gt;   1:&lt;/span&gt; public static Func&lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;object&lt;/span&gt;, &lt;span style="color: #ff0000"&gt;DependencyObject&lt;/span&gt;, &lt;span style="color: #ff0000"&gt;object&lt;/span&gt;, &lt;span style="color: #ff0000"&gt;UIElement&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt; LocateForModel&lt;!--CRLF--&gt;    &lt;span style="color: #606060" id="lnum2"&gt;   2:&lt;/span&gt; public static Func&lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;Type&lt;/span&gt;, &lt;span style="color: #ff0000"&gt;DependencyObject&lt;/span&gt;, &lt;span style="color: #ff0000"&gt;object&lt;/span&gt;, &lt;span style="color: #ff0000"&gt;UIElement&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt; LocateForModelType &lt;!--CRLF--&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;CM中大量使用了Func替换原有实现来完成多态，LocateForModel和LocateForModelType分别传入ViewModel的实例或者类型来返回对应的View，这两个名字有点不给力，我觉得换成GetCorrespondingView更直接一点。&lt;/p&gt;&lt;p&gt;那么这个根据ViewModel来找到View的实现是如何完成的呢？这个实现分两步，第一步，根据ViewModel来找到对应的View的类型（Type）；第二步，调用反射Activator.CreateInstance(Type type)来创建View。&lt;/p&gt;&lt;p&gt;为了更方便的从ViewModel中操作View，CM提供了IViewAware来允许在ViewModel中缓存（Cache）对应的View，IViewAware的接口定义如下：&lt;/p&gt;&lt;div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 100%; padding-right: 4px; font-family: 'Courier New', courier, monospace; direction: ltr; font-size: 8pt; overflow: hidden; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"&gt;  &lt;div style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: hidden; padding-top: 0px" id="codeSnippet"&gt;    &lt;span style="color: #606060" id="lnum1"&gt;   1:&lt;/span&gt; public interface IViewAware&lt;!--CRLF--&gt;    &lt;span style="color: #606060" id="lnum2"&gt;   2:&lt;/span&gt; {&lt;!--CRLF--&gt;    &lt;span style="color: #606060" id="lnum3"&gt;   3:&lt;/span&gt;     void AttachView(object view, object context = null);&lt;!--CRLF--&gt;    &lt;span style="color: #606060" id="lnum4"&gt;   4:&lt;/span&gt;     object GetView(object context = null);&lt;!--CRLF--&gt;    &lt;span style="color: #606060" id="lnum5"&gt;   5:&lt;/span&gt;     event EventHandler&lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;ViewAttachedEventArgs&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt; ViewAttached;&lt;!--CRLF--&gt;    &lt;span style="color: #606060" id="lnum6"&gt;   6:&lt;/span&gt; }&lt;!--CRLF--&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;ViewAware是IViewAware的默认实现类。当ViewModel和View被绑定到一起后，IViewAware的AttachView方法被调用，你可以重载OnViewAttached方法来针对View做一定处理，如注册View的事件（要小心事件的强引用）。当View被加载到VirualTree后，ViewAware的OnViewLoaded方法被调用，可以在这里遍历View的VisualTree做相应处理。&lt;/p&gt;&lt;p&gt;ViewLocator调用LocateForModel时也会首先判断ViewModel是不是实现了IViewAware并且已经缓存了View，如果是，那么不重新生成View而是直接返回缓存的View。这里就回到第一步，如何通过ViewModel来找到对应View的类型（Type）。&lt;/p&gt;&lt;h1 style="padding-bottom: 5px; background-color: gray; margin-top: 24px; padding-left: 5px; padding-right: 5px; margin-bottom: 12px; color: white; font-size: 26px; font-weight: normal; padding-top: 5px"&gt;NameTransformer&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;CM使用NameTransformer来通过正则表达式推算出可能存在的View的类型，这个实现是这样的：&lt;/p&gt;&lt;p&gt;NameTransformer中定义了ReplacePattern（替换规则），ReplaceValue（替换值），GlobalFilterPattern（过滤规则）通过正则表达式来做推算工作。比如说把ReplacePattern设置为ViewModel$，把ReplaceValue设置为View，这条规则（Rule）的意义是把字符串以ViewModel结尾的部分替换成View。比如传入的ViewModel类型是Illusion.ViewModels.ShellViewModel，替换之后返回的类型是Illusion.ViewModels.ShellView。&lt;/p&gt;&lt;p&gt;ViewLocator默认实现了5条规则，分别是&lt;/p&gt;&lt;ol&gt;  &lt;li&gt;去掉最末尾的View； &lt;/li&gt;  &lt;li&gt;把末尾ViewModel替换成View； &lt;/li&gt;  &lt;li&gt;把末尾的PageViewModel替换成Page； &lt;/li&gt;  &lt;li&gt;把Illusion.ViewModels.ShellViewModel替换成Illusion.Views.ShellView（替换ViewModels &amp;#8211;&amp;gt; Views，ShellViewModel &amp;#8211;&amp;gt; ShellView） &lt;/li&gt;  &lt;li&gt;把Illusion.ViewModels.ShellPageViewModel替换成Illusion.Views.ShellPage（同上） &lt;/li&gt;&lt;/ol&gt;&lt;p&gt;对实际项目来说，如果我们遵守着CM建议的命名规则，Illusion.ViewModels.ShellViewModel &amp;#8211;&amp;gt;Illusion.Views.ShellView，CM会自动找到对应的View。如果我们把ViewModel和View分离，没有遵循CM建议的命名规则，那么就要我们在ViewLocator的NameTransformer中添加对应的规则来帮助ViewLocator找到对应的View类型。&lt;/p&gt;&lt;p&gt;CM通过ViewLocator查询到对应View的类型后，其实获得的是一个字符串（String），CM要通过程序集（Assembly）来获取真正的类型（Type）。CM没有遍历Appdomain中的全部程序集，而是新建了一个AssemblySource来保存查询范围的程序集。你可以重载BootStrapper中的SelectAssemblies来返回查询范围的程序集，也可以调用AssemblySource的Add、AddRange方法来加入新的Assembly。&lt;/p&gt;&lt;p&gt;比如我们使用DirectoryCatalog来监视插件，对应的View类型在插件中，那么我们需要把插件对应的Assembly加入到AssemblySource中，否则ViewLocator是无法找到对应的View的。CM在View和ViewModel匹配处的设计思路是提供了一些实现和扩展的空间，但还不是那么十分智能，需要我们根据项目加入一些定制来满足要求。&lt;/p&gt;&lt;p&gt;当然也可以不使用View和ViewModel的智能匹配，手动创建View和ViewModel，然后ViewModelBinder的Bind方法来手动把View和ViewModel绑定在一起。&lt;/p&gt;&lt;h1 style="padding-bottom: 5px; background-color: gray; margin-top: 24px; padding-left: 5px; padding-right: 5px; margin-bottom: 12px; color: white; font-size: 26px; font-weight: normal; padding-top: 5px"&gt;View-First&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;在WP7环境中，推荐使用View-First模式，通过View来查询到对应的ViewModel，再把他们绑定到一起。这个实现原理以及匹配规则同ViewModel-First，这里就不做介绍了。&lt;/p&gt;&lt;h1 style="padding-bottom: 5px; background-color: gray; margin-top: 24px; padding-left: 5px; padding-right: 5px; margin-bottom: 12px; color: white; font-size: 26px; font-weight: normal; padding-top: 5px"&gt;Action Convention&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;在前篇&lt;a href="http://www.cnblogs.com/Zhouyongh/archive/2011/04/22/2018989.html"&gt;文章&lt;/a&gt;介绍过的Action中，我们使用类似&lt;/p&gt;&lt;div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 100%; padding-right: 4px; font-family: 'Courier New', courier, monospace; direction: ltr; font-size: 8pt; overflow: hidden; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"&gt;  &lt;div style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: hidden; padding-top: 0px" id="codeSnippet"&gt;    &lt;span style="color: #606060" id="lnum1"&gt;   1:&lt;/span&gt; &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;Button&lt;/span&gt; &lt;span style="color: #ff0000"&gt;cm:Message&lt;/span&gt;.&lt;span style="color: #ff0000"&gt;Attach&lt;/span&gt;&lt;span style="color: #0000ff"&gt;="[Event MouseEnter] = [Action Show('Enter')];  &lt;/span&gt;&lt;!--CRLF--&gt;    &lt;span style="color: #606060" id="lnum2"&gt;   2:&lt;/span&gt;                            [Event MouseLeave] = [Action Show('Leave')]" &lt;span style="color: #0000ff"&gt;/&amp;gt;&lt;/span&gt;&lt;!--CRLF--&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;就是使用了Action Convention，CM负责把Attach后面的字符串转化为对应的Action，这里的扩展空间不大，不细谈它了。&lt;/p&gt;&lt;h1 style="padding-bottom: 5px; background-color: gray; margin-top: 24px; padding-left: 5px; padding-right: 5px; margin-bottom: 12px; color: white; font-size: 26px; font-weight: normal; padding-top: 5px"&gt;Property Convention&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;这是CM中强大的一部分，其中的细节包括ElementConvention都很有意思，那么，就下篇吧。 ^_^&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;div&gt;&lt;span style="line-height: 25px; color: #333333"&gt;&lt;span style="line-height: 25px; background-color: #ffffff; font-family: georgia; color: #333333"&gt;&lt;span style="padding-bottom: 0px; line-height: 21px; margin: 0px; padding-left: 0px; padding-right: 0px; font-family: 宋体; color: black; font-size: 9pt; padding-top: 0px"&gt;作者：&lt;/span&gt;&lt;span style="padding-bottom: 0px; line-height: 21px; margin: 0px; padding-left: 0px; padding-right: 0px; font-family: verdana, sans-serif; color: black; font-size: 9pt; padding-top: 0px"&gt;&lt;a style="border-bottom: 1px dashed; padding-bottom: 0px; margin: 0px; outline-style: none; outline-color: ; padding-left: 0px; padding-right: 0px; color: #3d81ee; text-decoration: none; padding-top: 0px" href="http://www.cnblogs.com/Zhouyongh" target="_blank"&gt;&lt;span style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; font-family: 宋体; color: #ff6600; text-decoration: none; padding-top: 0px"&gt;周永恒&lt;/span&gt;&lt;/a&gt;         &lt;br style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px" /&gt;&lt;/span&gt;&lt;span style="padding-bottom: 0px; line-height: 21px; margin: 0px; padding-left: 0px; padding-right: 0px; font-family: 宋体; color: black; font-size: 9pt; padding-top: 0px"&gt;出处：&lt;/span&gt;&lt;span style="padding-bottom: 0px; line-height: 21px; margin: 0px; padding-left: 0px; padding-right: 0px; font-family: verdana, sans-serif; color: black; font-size: 9pt; padding-top: 0px"&gt;&lt;a style="border-bottom: 1px dashed; padding-bottom: 0px; margin: 0px; outline-style: none; outline-color: ; padding-left: 0px; padding-right: 0px; color: #3d81ee; text-decoration: none; padding-top: 0px" href="http://www.cnblogs.com/Zhouyongh" target="_blank"&gt;&lt;span style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; color: #ff6600; text-decoration: none; padding-top: 0px"&gt;http://www.cnblogs.com/Zhouyongh&lt;/span&gt;&lt;/a&gt;         &lt;br style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px" /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;p&gt;&lt;span style="line-height: 25px; font-family: 宋体; color: #333333; font-size: 12px" class="Apple-style-span"&gt;本文版权归作者和博客园共有，欢迎转载，但未经作者同意必须保留此段声明，且在文章页面明显位置给出原文连接，否则保留追究法律责任的权利。&lt;/span&gt;&lt;/p&gt;&lt;img src="http://www.cnblogs.com/Zhouyongh/aggbug/2111716.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/Zhouyongh/archive/2011/07/20/2111716.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/Zhouyongh/archive/2011/07/18/2109345.html</id><title type="text">Illusion = Caliburn.Micro + MEF</title><summary type="text">准备使用Caliburn.Micro结合MEF写一个类似于VS2010的IDE框架，支持插件开发，Menu、Toolbar等的可配置性，还有一些功能如：Option，多语言，换肤等。一方面作为技术沉淀，一方面也可以为新入WPF或者对Caliburn.Micro感兴趣的朋友们做一个指导。</summary><published>2011-07-18T04:05:00Z</published><updated>2011-07-18T04:05:00Z</updated><author><name>周永恒</name><uri>http://www.cnblogs.com/Zhouyongh/</uri></author><link rel="alternate" href="http://www.cnblogs.com/Zhouyongh/archive/2011/07/18/2109345.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/Zhouyongh/archive/2011/07/18/2109345.html"/><content type="html">&lt;h1 style="padding-bottom: 5px; background-color: gray; margin-top: 24px; padding-left: 5px; padding-right: 5px; margin-bottom: 12px; color: white; font-size: 26px; font-weight: normal; padding-top: 5px"&gt;前言&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;准备使用&lt;a href="http://caliburnmicro.codeplex.com/"&gt;Caliburn.Micro&lt;/a&gt;结合&lt;a href="http://mef.codeplex.com/"&gt;MEF&lt;/a&gt;写一个类似于VS2010的IDE框架，支持插件开发，Menu、Toolbar等的可配置性，还有一些功能如：Option，多语言，换肤等。一方面作为技术沉淀，一方面也可以为新入WPF或者对Caliburn.Micro感兴趣的朋友们做一个指导。&lt;/p&gt;  &lt;p&gt;没想到什么太好的名字，项目起名为Illusion，希望不是个幻觉，&lt;img style="border-bottom-style: none; border-left-style: none; border-top-style: none; border-right-style: none" class="wlEmoticon wlEmoticon-shifty" alt="Shifty" src="http://images.cnblogs.com/cnblogs_com/Zhouyongh/201107/20110718115356471.png" /&gt;。 项目的出发点也不复杂，主要想使用MEF来做插件开发，通过DirectoryCatalog来做插件检查，使用Export/Import构建Menu，Toolbar等。Caliburn.Micro是一个开源框架，框架基于MVVM模式，代码简洁而不简单，是企业级项目开发的一把利器。&lt;/p&gt;  &lt;h1 style="padding-bottom: 5px; background-color: gray; margin-top: 24px; padding-left: 5px; padding-right: 5px; margin-bottom: 12px; color: white; font-size: 26px; font-weight: normal; padding-top: 5px"&gt;实现&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;工程目录如下：&lt;/p&gt;  &lt;p&gt;&lt;a href="http://images.cnblogs.com/cnblogs_com/Zhouyongh/201107/201107181153567090.png"&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="Illusion" border="0" alt="Illusion" src="http://images.cnblogs.com/cnblogs_com/Zhouyongh/201107/201107181153562946.png" width="200" height="402" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;Illusion工程是核心的框架（Framework），Illusion.Demo是使用Illusion的EXE工程，AddIns文件夹下下有一些插件工程，项目使用了开源比较成熟的AvalonDock做停靠窗口。&lt;/p&gt;  &lt;p&gt;运行起来的程序：&lt;/p&gt;  &lt;p&gt;&lt;a href="http://images.cnblogs.com/cnblogs_com/Zhouyongh/201107/201107181153561517.png"&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="UIW" border="0" alt="UIW" src="http://images.cnblogs.com/cnblogs_com/Zhouyongh/201107/201107181153568453.png" width="693" height="455" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;项目提出了两个概念：Part，Screen。如上图所示，Menu和Toolbar的子项称为Part，停靠的窗口Project等称为Screen。&lt;/p&gt;  &lt;h1 style="padding-bottom: 5px; background-color: gray; margin-top: 24px; padding-left: 5px; padding-right: 5px; margin-bottom: 12px; color: white; font-size: 26px; font-weight: normal; padding-top: 5px"&gt;配置&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;添加Menu的代码如下：&lt;/p&gt;  &lt;div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 100%; padding-right: 4px; font-family: 'Courier New', courier, monospace; direction: ltr; font-size: 8pt; overflow: hidden; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"&gt;   &lt;div style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: hidden; padding-top: 0px" id="codeSnippet"&gt;     &lt;span style="color: #606060" id="lnum1"&gt;   1:&lt;/span&gt; [MenuPart(BaseMenu = WorkbenchName.WindowPart, PreviousMenu = WorkbenchName.CloseDocumentsPart)]&lt;!--CRLF--&gt;    &lt;span style="color: #606060" id="lnum2"&gt;   2:&lt;/span&gt; public class ResetLayoutPart : MenuPart&lt;!--CRLF--&gt;    &lt;span style="color: #606060" id="lnum3"&gt;   3:&lt;/span&gt; {&lt;!--CRLF--&gt;    &lt;span style="color: #606060" id="lnum4"&gt;   4:&lt;/span&gt;     public ResetLayoutPart()&lt;!--CRLF--&gt;    &lt;span style="color: #606060" id="lnum5"&gt;   5:&lt;/span&gt;         : base(WorkbenchName.ResetLayoutPart)&lt;!--CRLF--&gt;    &lt;span style="color: #606060" id="lnum6"&gt;   6:&lt;/span&gt;     {&lt;!--CRLF--&gt;    &lt;span style="color: #606060" id="lnum7"&gt;   7:&lt;/span&gt;         Icon = "Icons.16x16.CopyIcon";&lt;!--CRLF--&gt;    &lt;span style="color: #606060" id="lnum8"&gt;   8:&lt;/span&gt;     }&lt;!--CRLF--&gt;    &lt;span style="color: #606060" id="lnum9"&gt;   9:&lt;/span&gt;&amp;nbsp; &lt;!--CRLF--&gt;    &lt;span style="color: #606060" id="lnum10"&gt;  10:&lt;/span&gt;     public override void Execute()&lt;!--CRLF--&gt;    &lt;span style="color: #606060" id="lnum11"&gt;  11:&lt;/span&gt;     {&lt;!--CRLF--&gt;    &lt;span style="color: #606060" id="lnum12"&gt;  12:&lt;/span&gt;         base.Execute();&lt;!--CRLF--&gt;    &lt;span style="color: #606060" id="lnum13"&gt;  13:&lt;/span&gt;     }&lt;!--CRLF--&gt;    &lt;span style="color: #606060" id="lnum14"&gt;  14:&lt;/span&gt; }&lt;!--CRLF--&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;第一行的MenuPart继承自ExportAttribute，等同于[Export(typeof(IMenuPart)]，BaseMenu和PreviousMenu指定了ResetLayoutPart的父项和它的上一个Menu，以此来确定Menu的位置。当Menu点击时，Execute方法被调用，在此写入Menu的执行代码。可以重载CanExecute来决定Menu是否可调用，设置IsVisible属性来决定Menu是否可见。&lt;/p&gt;&lt;p&gt;通常情况下，很多Menu同时也会在Toolbar上出现，为了减少重复代码，定义了MenuToolPart类指定该Part既可以是Menu也可以充当Toolbar。&lt;/p&gt;&lt;p&gt;Screen的添加方法和Part类似，略去不讲。&lt;/p&gt;&lt;h1 style="padding-bottom: 5px; background-color: gray; margin-top: 24px; padding-left: 5px; padding-right: 5px; margin-bottom: 12px; color: white; font-size: 26px; font-weight: normal; padding-top: 5px"&gt;其他&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;可以添加插件工程导出Part或Screen等。&lt;/p&gt;&lt;p&gt;&lt;a href="http://images.cnblogs.com/cnblogs_com/Zhouyongh/201107/201107181153565944.png"&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="add" border="0" alt="add" src="http://images.cnblogs.com/cnblogs_com/Zhouyongh/201107/201107181153569848.png" width="170" height="125" /&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;程序运行后，DirectoryCatalog会监视AddIns目录下所有插件并导入。&lt;/p&gt;&lt;p&gt;其他一些Option，多语言，换肤功能请参见代码，这里不一一介绍了。&lt;/p&gt;&lt;h1 style="padding-bottom: 5px; background-color: gray; margin-top: 24px; padding-left: 5px; padding-right: 5px; margin-bottom: 12px; color: white; font-size: 26px; font-weight: normal; padding-top: 5px"&gt;闲聊&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;Illusion项目陆陆续续写了一周多，想法变为代码，激情过后都是空虚，闭门造车也需要耐心，这些年业余写了好多代码后来都扔一边去了。&lt;/p&gt;&lt;p&gt;把代码上传上来和大家交流一下，如果有对这方面感兴趣的朋友欢迎和我联系，也不加什么PL协议了，有不足之处欢迎指正，有能用之处欢迎拿去用。如果真能对您有所帮助的话，希望你能留个言或者顶一下，江湖话说：&lt;/p&gt;&lt;blockquote style='border:2px solid #EFEFEF;color:#333333;padding:5px 10px;'&gt;  &lt;p&gt;&lt;font size="3"&gt;做兄弟，要厚道&lt;/font&gt;&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;Illusion的代码下载请点击&lt;a href="http://files.cnblogs.com/Zhouyongh/Illusion.rar"&gt;这里&lt;/a&gt;，使用了System.Windows.Interactivity，需要Expression Blend4以上版本支持。&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;div&gt;&lt;span style="line-height: 25px; color: #333333"&gt;&lt;span style="line-height: 25px; background-color: #ffffff; font-family: georgia; color: #333333"&gt;&lt;span style="padding-bottom: 0px; line-height: 21px; margin: 0px; padding-left: 0px; padding-right: 0px; font-family: 宋体; color: black; font-size: 9pt; padding-top: 0px"&gt;作者：&lt;/span&gt;&lt;span style="padding-bottom: 0px; line-height: 21px; margin: 0px; padding-left: 0px; padding-right: 0px; font-family: verdana, sans-serif; color: black; font-size: 9pt; padding-top: 0px"&gt;&lt;a style="border-bottom: 1px dashed; padding-bottom: 0px; margin: 0px; outline-style: none; outline-color: ; padding-left: 0px; padding-right: 0px; color: #3d81ee; text-decoration: none; padding-top: 0px" href="http://www.cnblogs.com/Zhouyongh" target="_blank"&gt;&lt;span style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; font-family: 宋体; color: #ff6600; text-decoration: none; padding-top: 0px"&gt;周永恒&lt;/span&gt;&lt;/a&gt;         &lt;br style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px" /&gt;&lt;/span&gt;&lt;span style="padding-bottom: 0px; line-height: 21px; margin: 0px; padding-left: 0px; padding-right: 0px; font-family: 宋体; color: black; font-size: 9pt; padding-top: 0px"&gt;出处：&lt;/span&gt;&lt;span style="padding-bottom: 0px; line-height: 21px; margin: 0px; padding-left: 0px; padding-right: 0px; font-family: verdana, sans-serif; color: black; font-size: 9pt; padding-top: 0px"&gt;&lt;a style="border-bottom: 1px dashed; padding-bottom: 0px; margin: 0px; outline-style: none; outline-color: ; padding-left: 0px; padding-right: 0px; color: #3d81ee; text-decoration: none; padding-top: 0px" href="http://www.cnblogs.com/Zhouyongh" target="_blank"&gt;&lt;span style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; color: #ff6600; text-decoration: none; padding-top: 0px"&gt;http://www.cnblogs.com/Zhouyongh&lt;/span&gt;&lt;/a&gt;         &lt;br style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px" /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;p&gt;&lt;span style="line-height: 25px; font-family: 宋体; color: #333333; font-size: 12px" class="Apple-style-span"&gt;本文版权归作者和博客园共有，欢迎转载，但未经作者同意必须保留此段声明，且在文章页面明显位置给出原文连接，否则保留追究法律责任的权利。&lt;/span&gt;&lt;/p&gt;&lt;img src="http://www.cnblogs.com/Zhouyongh/aggbug/2109345.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/Zhouyongh/archive/2011/07/18/2109345.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/Zhouyongh/archive/2011/04/22/2018989.html</id><title type="text">解析Caliburn.Micro（二）</title><summary type="text">Caliburn.Micro是用于WPF,Silverlight，WP7的开源应用框架，本文主要介绍了Caliburn.Micro的Action，希望能给朋友们带来些帮助。</summary><published>2011-04-22T03:39:00Z</published><updated>2011-04-22T03:39:00Z</updated><author><name>周永恒</name><uri>http://www.cnblogs.com/Zhouyongh/</uri></author><link rel="alternate" href="http://www.cnblogs.com/Zhouyongh/archive/2011/04/22/2018989.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/Zhouyongh/archive/2011/04/22/2018989.html"/><content type="html">&lt;p&gt;书接&lt;a href="http://www.cnblogs.com/Zhouyongh/archive/2011/04/18/Caliburn.html"&gt;前文&lt;/a&gt;，前篇文章简略了介绍了一下Caliburn.Micro（简称CM），这篇文章来走入CM，看看它最有意思的Action。&lt;/p&gt;  &lt;h1 style="padding-bottom: 5px; background-color: gray; margin-top: 24px; padding-left: 5px; padding-right: 5px; margin-bottom: 12px; color: white; font-size: 26px; font-weight: normal; padding-top: 5px"&gt;运行CM&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;下载&lt;a href="http://caliburnmicro.codeplex.com/releases/view/64274"&gt;Caliburn.Micro&lt;/a&gt;，打开Template，拷贝Caliburn_Micro_WPF.zip到%userprofile%\Documents\Visual Studio 2010\Templates\ProjectTemplates\Visual C#\Windows，在Visual Studio 2010中新建工程，选择Visual C#&amp;#8212;Windows，可以看到Caliburn.Micro的模板，新建工程CaliburnMicroWPF1，如下：&lt;/p&gt;  &lt;p&gt;&lt;a href="http://images.cnblogs.com/cnblogs_com/Zhouyongh/201104/201104171718264071.png"&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="Capture" border="0" alt="Capture" src="http://images.cnblogs.com/cnblogs_com/Zhouyongh/201104/201104171718269926.png" width="254" height="213" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;Framework文件夹下就是Caliburn.Micro的源码，ShellView是主Window，ShellViewModel是ShellView的DataContext，这是一个标准的View-ViewModel模式。AppBootstrapper是启动加载器，可以配置CM的加载策略。&lt;/p&gt;  &lt;h1 style="padding-bottom: 5px; background-color: gray; margin-top: 24px; padding-left: 5px; padding-right: 5px; margin-bottom: 12px; color: white; font-size: 26px; font-weight: normal; padding-top: 5px"&gt;Bootstrapper&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;Bootstrapper的构造函数如下：&lt;/p&gt;  &lt;div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 100%; padding-right: 4px; font-family: 'Courier New', courier, monospace; direction: ltr; font-size: 8pt; overflow: hidden; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"&gt;   &lt;div style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: hidden; padding-top: 0px" id="codeSnippet"&gt;     &lt;span style="color: #606060" id="lnum1"&gt;   1:&lt;/span&gt; &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; Bootstrapper()&lt;!--CRLF--&gt;    &lt;span style="color: #606060" id="lnum2"&gt;   2:&lt;/span&gt; {&lt;!--CRLF--&gt;    &lt;span style="color: #606060" id="lnum3"&gt;   3:&lt;/span&gt;     &lt;span style="color: #0000ff"&gt;if&lt;/span&gt; (IsInDesignMode)&lt;!--CRLF--&gt;    &lt;span style="color: #606060" id="lnum4"&gt;   4:&lt;/span&gt;         StartDesignTime();&lt;!--CRLF--&gt;    &lt;span style="color: #606060" id="lnum5"&gt;   5:&lt;/span&gt;     &lt;span style="color: #0000ff"&gt;else&lt;/span&gt; StartRuntime();&lt;!--CRLF--&gt;    &lt;span style="color: #606060" id="lnum6"&gt;   6:&lt;/span&gt; }&lt;!--CRLF--&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;可以重载StartDesignTime来为Blend等配置Design时的数据，程序运行时，StartRunTime被调用，&lt;/p&gt;&lt;div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 100%; padding-right: 4px; font-family: 'Courier New', courier, monospace; direction: ltr; font-size: 8pt; overflow: hidden; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"&gt;  &lt;div style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: hidden; padding-top: 0px" id="codeSnippet"&gt;    &lt;span style="color: #606060" id="lnum1"&gt;   1:&lt;/span&gt; &lt;span style="color: #0000ff"&gt;protected&lt;/span&gt; &lt;span style="color: #0000ff"&gt;virtual&lt;/span&gt; &lt;span style="color: #0000ff"&gt;void&lt;/span&gt; StartRuntime()&lt;!--CRLF--&gt;    &lt;span style="color: #606060" id="lnum2"&gt;   2:&lt;/span&gt; {&lt;!--CRLF--&gt;    &lt;span style="color: #606060" id="lnum3"&gt;   3:&lt;/span&gt;     Execute.InitializeWithDispatcher();&lt;!--CRLF--&gt;    &lt;span style="color: #606060" id="lnum4"&gt;   4:&lt;/span&gt;     AssemblySource.Instance.AddRange(SelectAssemblies());&lt;!--CRLF--&gt;    &lt;span style="color: #606060" id="lnum5"&gt;   5:&lt;/span&gt;&amp;nbsp; &lt;!--CRLF--&gt;    &lt;span style="color: #606060" id="lnum6"&gt;   6:&lt;/span&gt;     Application = Application.Current;&lt;!--CRLF--&gt;    &lt;span style="color: #606060" id="lnum7"&gt;   7:&lt;/span&gt;     PrepareApplication();&lt;!--CRLF--&gt;    &lt;span style="color: #606060" id="lnum8"&gt;   8:&lt;/span&gt;&amp;nbsp; &lt;!--CRLF--&gt;    &lt;span style="color: #606060" id="lnum9"&gt;   9:&lt;/span&gt;     Configure();&lt;!--CRLF--&gt;    &lt;span style="color: #606060" id="lnum10"&gt;  10:&lt;/span&gt;     IoC.GetInstance = GetInstance;&lt;!--CRLF--&gt;    &lt;span style="color: #606060" id="lnum11"&gt;  11:&lt;/span&gt;     IoC.GetAllInstances = GetAllInstances;&lt;!--CRLF--&gt;    &lt;span style="color: #606060" id="lnum12"&gt;  12:&lt;/span&gt;     IoC.BuildUp = BuildUp;&lt;!--CRLF--&gt;    &lt;span style="color: #606060" id="lnum13"&gt;  13:&lt;/span&gt; }&lt;!--CRLF--&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;可以重载PrepareApplication监听Application的事件，或者重载Configure函数来设置&lt;a href="http://en.wikipedia.org/wiki/Inversion_of_control"&gt;IOC&lt;/a&gt;（Inversion of control/控制反转）容器。比较有意思的是后三个IoC的静态字段：&lt;/p&gt;&lt;div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 100%; padding-right: 4px; font-family: 'Courier New', courier, monospace; direction: ltr; font-size: 8pt; overflow: hidden; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"&gt;  &lt;div style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: hidden; padding-top: 0px" id="codeSnippet"&gt;    &lt;span style="color: #606060" id="lnum1"&gt;   1:&lt;/span&gt; &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;static&lt;/span&gt; &lt;span style="color: #0000ff"&gt;class&lt;/span&gt; IoC&lt;!--CRLF--&gt;    &lt;span style="color: #606060" id="lnum2"&gt;   2:&lt;/span&gt; {&lt;!--CRLF--&gt;    &lt;span style="color: #606060" id="lnum3"&gt;   3:&lt;/span&gt;     &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;static&lt;/span&gt; Func&amp;lt;Type, &lt;span style="color: #0000ff"&gt;string&lt;/span&gt;, &lt;span style="color: #0000ff"&gt;object&lt;/span&gt;&amp;gt; GetInstance;&lt;!--CRLF--&gt;    &lt;span style="color: #606060" id="lnum4"&gt;   4:&lt;/span&gt;     &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;static&lt;/span&gt; Func&amp;lt;Type, IEnumerable&amp;lt;&lt;span style="color: #0000ff"&gt;object&lt;/span&gt;&amp;gt;&amp;gt; GetAllInstances;&lt;!--CRLF--&gt;    &lt;span style="color: #606060" id="lnum5"&gt;   5:&lt;/span&gt;     &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;static&lt;/span&gt; Action&amp;lt;&lt;span style="color: #0000ff"&gt;object&lt;/span&gt;&amp;gt; BuildUp;&lt;!--CRLF--&gt;    &lt;span style="color: #606060" id="lnum6"&gt;   6:&lt;/span&gt;&amp;nbsp; &lt;!--CRLF--&gt;    &lt;span style="color: #606060" id="lnum7"&gt;   7:&lt;/span&gt;     &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;static&lt;/span&gt; T Get&amp;lt;T&amp;gt;()&lt;!--CRLF--&gt;    &lt;span style="color: #606060" id="lnum8"&gt;   8:&lt;/span&gt;     {&lt;!--CRLF--&gt;    &lt;span style="color: #606060" id="lnum9"&gt;   9:&lt;/span&gt;         &lt;span style="color: #0000ff"&gt;return&lt;/span&gt; (T)GetInstance(&lt;span style="color: #0000ff"&gt;typeof&lt;/span&gt;(T), &lt;span style="color: #0000ff"&gt;null&lt;/span&gt;);&lt;!--CRLF--&gt;    &lt;span style="color: #606060" id="lnum10"&gt;  10:&lt;/span&gt;     }&lt;!--CRLF--&gt;    &lt;span style="color: #606060" id="lnum11"&gt;  11:&lt;/span&gt;&amp;nbsp; &lt;!--CRLF--&gt;    &lt;span style="color: #606060" id="lnum12"&gt;  12:&lt;/span&gt;     &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;static&lt;/span&gt; T Get&amp;lt;T&amp;gt;(&lt;span style="color: #0000ff"&gt;string&lt;/span&gt; key)&lt;!--CRLF--&gt;    &lt;span style="color: #606060" id="lnum13"&gt;  13:&lt;/span&gt;     {&lt;!--CRLF--&gt;    &lt;span style="color: #606060" id="lnum14"&gt;  14:&lt;/span&gt;         &lt;span style="color: #0000ff"&gt;return&lt;/span&gt; (T)GetInstance(&lt;span style="color: #0000ff"&gt;typeof&lt;/span&gt;(T), key);&lt;!--CRLF--&gt;    &lt;span style="color: #606060" id="lnum15"&gt;  15:&lt;/span&gt;     }&lt;!--CRLF--&gt;    &lt;span style="color: #606060" id="lnum16"&gt;  16:&lt;/span&gt; }&lt;!--CRLF--&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;IoC是一个静态类，用来提供IOC的支持，其中的Get方法通过类型来查询注册的实例。通常的做法一般是把IoC定义为虚基类，子类通过重载其中的Get方法来实现自己IoC逻辑。IoC类通过3个静态Func来实现多态，AppBootstrapper使用了MEF作为I默认的IOC实现。可以重载Bootstrapper来使用其他的IOC，如Unity等。&lt;/p&gt;&lt;h1 style="padding-bottom: 5px; background-color: gray; margin-top: 24px; padding-left: 5px; padding-right: 5px; margin-bottom: 12px; color: white; font-size: 26px; font-weight: normal; padding-top: 5px"&gt;MEF&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;MEF（Managed Extensibility Framework），在.net4.0后被正式引入.net framework中，通过简单的附加Export，Import标签，表明组件之间的&amp;#8220;消费&amp;#8221;和&amp;#8220;提供&amp;#8221;关系，MEF在底层动态的完成组件识别，装配工作。MEF的出现，使开发基于插件架构的应用系统变得更加简单，本文不是详细介绍MEF的，作为默认的IoC实现，Caliburn.Micro使用了MEF。&lt;/p&gt;&lt;p&gt;这里的使用，只是默认采用了MEF，具体说是使用了其中的CompositionContainer作为IoC容器，CM本身和MEF并没有什么联系，让我们把目光集中到CM上，从一个最简单的应用开始，走入Caliburn.Micro。&lt;/p&gt;&lt;h1 style="padding-bottom: 5px; background-color: gray; margin-top: 24px; padding-left: 5px; padding-right: 5px; margin-bottom: 12px; color: white; font-size: 26px; font-weight: normal; padding-top: 5px"&gt;第一个应用程序&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;在ShellView中加入一个Button，从Blend&amp;#8212;Assets中加入ActionMessage到Button，设置Trigger的EventName为Click。切换到ShellViewModel中，加入Show函数&lt;/p&gt;&lt;div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 100%; padding-right: 4px; font-family: 'Courier New', courier, monospace; direction: ltr; font-size: 8pt; overflow: hidden; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"&gt;  &lt;div style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: hidden; padding-top: 0px" id="codeSnippet"&gt;    &lt;span style="color: #606060" id="lnum1"&gt;   1:&lt;/span&gt; &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;void&lt;/span&gt; Show()&lt;!--CRLF--&gt;    &lt;span style="color: #606060" id="lnum2"&gt;   2:&lt;/span&gt; {&lt;!--CRLF--&gt;    &lt;span style="color: #606060" id="lnum3"&gt;   3:&lt;/span&gt;     MessageBox.Show(&lt;span style="color: #006080"&gt;"Hello"&lt;/span&gt;);&lt;!--CRLF--&gt;    &lt;span style="color: #606060" id="lnum4"&gt;   4:&lt;/span&gt; }&lt;!--CRLF--&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;回到ShellView中，设置ActionMessage的MethodName为Show，如图：&lt;/p&gt;&lt;p&gt;&lt;a href="http://images.cnblogs.com/cnblogs_com/Zhouyongh/201104/201104220220398276.png"&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: block; float: none; border-top-width: 0px; border-bottom-width: 0px; margin-left: auto; border-left-width: 0px; margin-right: auto; padding-top: 0px" title="Capture" border="0" alt="Capture" src="http://images.cnblogs.com/cnblogs_com/Zhouyongh/201104/201104220220396848.png" width="348" height="241" /&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;程序运行后，点击Button，Show函数被调用。&lt;/p&gt;&lt;p&gt;这是一个最简单的ActionMessage用法，让我们来分析一下这个过程。&lt;/p&gt;&lt;p&gt;简单来说是Button点击后方法被执行，最原始的做法应该是在Button的XAML中加入Click=&amp;#8221;HandleBtnClick&amp;#8221;把事件绑定到后台处理函数。后来MVVM开始流行，设置ShellViewModel作为ShellView的DataContext，在ShellViewModel中提供ICommand--ShowCommand，然后把Button的Command设置为Command=&amp;#8220;{Binding ShowCommand}&amp;#8221;。&lt;/p&gt;&lt;p&gt;这里ActionMessage处理的事情有二：&lt;/p&gt;&lt;ol&gt;  &lt;li&gt;通过名字匹配自动把ShellViewModel设置为ShellView的DataContext。 &lt;/li&gt;  &lt;li&gt;通过反射用名字取到对应的方法，Invoke该方法。 &lt;/li&gt;&lt;/ol&gt;&lt;p&gt;这个思路是很清晰的，第一步的匹配是CM中的一个特色Convention，自动匹配XXViewModel和XXView。第二步会在前面查到的XXViewModel中查询名字为Show的MethodInfo，然后反射调用。&lt;/p&gt;&lt;h1 style="padding-bottom: 5px; background-color: gray; margin-top: 24px; padding-left: 5px; padding-right: 5px; margin-bottom: 12px; color: white; font-size: 26px; font-weight: normal; padding-top: 5px"&gt;ActionMessage&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;ActionMessage的设计思路并不复杂，它继承自TriggerAction&amp;lt;FrameworkElement&amp;gt;，可以作用于FrameworkElement。程序运行后，TriggerAction会被Attach到其对应的FrameworkElement上，ActionMessage有两个重要的属性：MethodName和Parameters，前者是需要执行方法的名字，后者是一个集合，表示传入的参数。MethodName前面已经介绍过了，让我们来看一下Parameters的用法。&lt;/p&gt;&lt;p&gt;最简单的应用，可以修改前面ViewModel中的Show()方法为Show(string message)，然后在Parameters里传入Show方法的参数，如&lt;/p&gt;&lt;div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 100%; padding-right: 4px; font-family: 'Courier New', courier, monospace; direction: ltr; font-size: 8pt; overflow: hidden; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"&gt;  &lt;div style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: hidden; padding-top: 0px" id="codeSnippet"&gt;    &lt;span style="color: #606060" id="lnum1"&gt;   1:&lt;/span&gt; &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;cm:ActionMessage&lt;/span&gt; &lt;span style="color: #ff0000"&gt;MethodName&lt;/span&gt;&lt;span style="color: #0000ff"&gt;="Show"&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;!--CRLF--&gt;    &lt;span style="color: #606060" id="lnum2"&gt;   2:&lt;/span&gt;     &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;cm:Parameter&lt;/span&gt; &lt;span style="color: #ff0000"&gt;Value&lt;/span&gt;&lt;span style="color: #0000ff"&gt;="woo~"&lt;/span&gt;&lt;span style="color: #0000ff"&gt;/&amp;gt;&lt;/span&gt;&lt;!--CRLF--&gt;    &lt;span style="color: #606060" id="lnum3"&gt;   3:&lt;/span&gt; &lt;span style="color: #0000ff"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000"&gt;cm:ActionMessage&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;!--CRLF--&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;Show方法执行后，woo~参数被传入，Parameters也可以传入多个参数，当找不到匹配参数的方法时会抛出异常。CM对Parameter的Value参数进行了扩展：&lt;/p&gt;&lt;ol&gt;  &lt;li&gt;Value支持绑定，可以写成Value={Binding ElementName=XX, Path=XX}的方式 &lt;/li&gt;  &lt;li&gt;CM提供了MessageBinder类对Message进行解析，可以指定$eventArgs传入执行方法的arg，指定$source传入绑定的UI，$dataContext传入对应的DataContext等。可以扩展MessageBinder的SpecialValues向其中加入更多的解析规则，默认的这些特殊解析都是以$为开头的。 &lt;/li&gt;&lt;/ol&gt;&lt;h1 style="padding-bottom: 5px; background-color: gray; margin-top: 24px; padding-left: 5px; padding-right: 5px; margin-bottom: 12px; color: white; font-size: 26px; font-weight: normal; padding-top: 5px"&gt;Message.Attach&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;前面ActionMessage的写法是&lt;/p&gt;&lt;div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 100%; padding-right: 4px; font-family: 'Courier New', courier, monospace; direction: ltr; font-size: 8pt; overflow: hidden; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"&gt;  &lt;div style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: hidden; padding-top: 0px" id="codeSnippet"&gt;    &lt;span style="color: #606060" id="lnum1"&gt;   1:&lt;/span&gt; &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;Button&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;!--CRLF--&gt;    &lt;span style="color: #606060" id="lnum2"&gt;   2:&lt;/span&gt;     &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;i:Interaction.Triggers&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;!--CRLF--&gt;    &lt;span style="color: #606060" id="lnum3"&gt;   3:&lt;/span&gt;         &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;i:EventTrigger&lt;/span&gt; &lt;span style="color: #ff0000"&gt;EventName&lt;/span&gt;&lt;span style="color: #0000ff"&gt;="Click"&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;!--CRLF--&gt;    &lt;span style="color: #606060" id="lnum4"&gt;   4:&lt;/span&gt;             &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;cm:ActionMessage&lt;/span&gt; &lt;span style="color: #ff0000"&gt;MethodName&lt;/span&gt;&lt;span style="color: #0000ff"&gt;="Show"&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;!--CRLF--&gt;    &lt;span style="color: #606060" id="lnum5"&gt;   5:&lt;/span&gt;                 &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;cm:Parameter&lt;/span&gt; &lt;span style="color: #ff0000"&gt;Value&lt;/span&gt;&lt;span style="color: #0000ff"&gt;="woo~"&lt;/span&gt;&lt;span style="color: #0000ff"&gt;/&amp;gt;&lt;/span&gt;&lt;!--CRLF--&gt;    &lt;span style="color: #606060" id="lnum6"&gt;   6:&lt;/span&gt;             &lt;span style="color: #0000ff"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000"&gt;cm:ActionMessage&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;!--CRLF--&gt;    &lt;span style="color: #606060" id="lnum7"&gt;   7:&lt;/span&gt;         &lt;span style="color: #0000ff"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000"&gt;i:EventTrigger&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;!--CRLF--&gt;    &lt;span style="color: #606060" id="lnum8"&gt;   8:&lt;/span&gt;     &lt;span style="color: #0000ff"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000"&gt;i:Interaction.Triggers&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;!--CRLF--&gt;    &lt;span style="color: #606060" id="lnum9"&gt;   9:&lt;/span&gt; &lt;span style="color: #0000ff"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000"&gt;Button&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;!--CRLF--&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;借助于Blend中的Interaction，把路由事件Click与ActionMessage连接起来，CM为ActionMessage提供了更为强大的Attach功能，可以把前面的代码改写成&lt;/p&gt;&lt;div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 100%; padding-right: 4px; font-family: 'Courier New', courier, monospace; direction: ltr; font-size: 8pt; overflow: hidden; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"&gt;  &lt;div style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: hidden; padding-top: 0px" id="codeSnippet"&gt;    &lt;span style="color: #606060" id="lnum1"&gt;   1:&lt;/span&gt; &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;Button&lt;/span&gt; &lt;span style="color: #ff0000"&gt;cm:Message&lt;/span&gt;.&lt;span style="color: #ff0000"&gt;Attach&lt;/span&gt;&lt;span style="color: #0000ff"&gt;="[Event Click] = [Action Show(&amp;#8216;woo~&amp;#8217;)]"&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;!--CRLF--&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;Message.Attach是CM定义的一个附加属性，CM会Parse这个Attach属性的值，以生成对应的Action。为了更好的解析，CM指定了一些规则，如上面的[Event Click] = [Action Show(&amp;#8216;woo~&amp;#8217;)]表示在Click这个路由事件发生时执行Show方法，方法的参数是woo~。&lt;/p&gt;&lt;p&gt;特殊符号里中括号[]表示对象，[Event Click]的第一个参数表示对象的种类是Event，第二个参数表示对象名字为Click；等号=用来连接Event和ActionMessage；小括号()表示传递的参数。可以用分号；来表示多个Event/ActionMessage对，如：&lt;/p&gt;&lt;div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 100%; padding-right: 4px; font-family: 'Courier New', courier, monospace; direction: ltr; font-size: 8pt; overflow: hidden; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"&gt;  &lt;div style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: hidden; padding-top: 0px" id="codeSnippet"&gt;    &lt;span style="color: #606060" id="lnum1"&gt;   1:&lt;/span&gt; &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;Button&lt;/span&gt; &lt;span style="color: #ff0000"&gt;cm:Message&lt;/span&gt;.&lt;span style="color: #ff0000"&gt;Attach&lt;/span&gt;&lt;span style="color: #0000ff"&gt;="&lt;font color="#000000"&gt;[Event MouseEnter] = [Action Show('Enter')];&lt;/font&gt;  &lt;/span&gt;&lt;!--CRLF--&gt;    &lt;span style="color: #606060" id="lnum2"&gt;   2:&lt;/span&gt;                            [Event MouseLeave] = [Action Show('Leave')]" &lt;span style="color: #0000ff"&gt;/&amp;gt;&lt;/span&gt;&lt;!--CRLF--&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;表示了两个Event/ActionMessage对。&lt;/p&gt;&lt;p&gt;小括号()传入参数时不仅可以传入字符串，也可以使用绑定，如：&lt;/p&gt;&lt;div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 100%; padding-right: 4px; font-family: 'Courier New', courier, monospace; direction: ltr; font-size: 8pt; overflow: hidden; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"&gt;  &lt;div style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: hidden; padding-top: 0px" id="codeSnippet"&gt;    &lt;span style="color: #606060" id="lnum1"&gt;   1:&lt;/span&gt; &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;TextBlock&lt;/span&gt; &lt;span style="color: #ff0000"&gt;x:Name&lt;/span&gt;&lt;span style="color: #0000ff"&gt;="txtBlock"&lt;/span&gt; &lt;span style="color: #ff0000"&gt;Text&lt;/span&gt;&lt;span style="color: #0000ff"&gt;="woo~"&lt;/span&gt;&lt;span style="color: #0000ff"&gt;/&amp;gt;&lt;/span&gt;&lt;!--CRLF--&gt;    &lt;span style="color: #606060" id="lnum2"&gt;   2:&lt;/span&gt; &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;Button&lt;/span&gt; &lt;span style="color: #ff0000"&gt;cm:Message&lt;/span&gt;.&lt;span style="color: #ff0000"&gt;Attach&lt;/span&gt;&lt;span style="color: #0000ff"&gt;="[Event Click] = [Action Show(txtBlock.Text)]"&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;!--CRLF--&gt;&lt;/div&gt;&lt;/div&gt;使用Show(txtBlock.Text)在调用Show时传入txtBlock的Text值，默认CM的查找规则是通过Visual Tree来查找，如果把txtBlock放在ContextMenu等不在Visual Tree的位置上时，绑定会查找不到对应的UI元素。 &lt;h1 style="padding-bottom: 5px; background-color: gray; margin-top: 24px; padding-left: 5px; padding-right: 5px; margin-bottom: 12px; color: white; font-size: 26px; font-weight: normal; padding-top: 5px"&gt;深入Action&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;前面一直在提ActionMessage，这里详细的挖一下CM的Action机制。&lt;/p&gt;&lt;p&gt;这个Action，简单来说就是在事件A发生时执行对象B的C方法，&lt;/p&gt;&lt;ol&gt;  &lt;li&gt;ActionMessage是继承自TriggerAction&amp;lt;FrameworkElement&amp;gt;的，TriggerAction来自于Blend的Interactivity，在事件A被执行时会调用到ActionMessage的Invoke方法。关于Blend的TriggerBase不是本文讨论的重点，只是说明事件A这一步由Blend保证完成。 &lt;/li&gt;  &lt;li&gt;在创建ActionMessage的时候设置了属性MethodName，这个MethodName指明了C方法，那么整个ActionMessage的关键就是如何找到对应的B对象。 &lt;/li&gt;&lt;/ol&gt;&lt;p&gt;Caliburn.Micro框架是基于MVVM的，如果你对MVVM无爱的话请无视Caliburn.Micro。MVVM（Model-View-ViewModel）,对View的操作要通过Command传递到VM。这里的B对象就指ViewModel，CM用Target来表示目标对象B，默认情况下Target等于控件的DataContext。CM提供了Action.Target附加属性允许设置Target，如&lt;/p&gt;&lt;div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 100%; padding-right: 4px; font-family: 'Courier New', courier, monospace; direction: ltr; font-size: 8pt; overflow: hidden; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"&gt;  &lt;div style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: hidden; padding-top: 0px" id="codeSnippet"&gt;    &lt;span style="color: #606060" id="lnum1"&gt;   1:&lt;/span&gt; &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;ListBox&lt;/span&gt; &lt;span style="color: #ff0000"&gt;x:Name&lt;/span&gt;&lt;span style="color: #0000ff"&gt;="lstBox"&lt;/span&gt;  &lt;span style="color: #ff0000"&gt;SelectionMode&lt;/span&gt;&lt;span style="color: #0000ff"&gt;="Extended"&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;!--CRLF--&gt;    &lt;span style="color: #606060" id="lnum2"&gt;   2:&lt;/span&gt;     &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;ListBoxItem&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;123&lt;span style="color: #0000ff"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000"&gt;ListBoxItem&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;!--CRLF--&gt;    &lt;span style="color: #606060" id="lnum3"&gt;   3:&lt;/span&gt;     &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;ListBoxItem&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;123&lt;span style="color: #0000ff"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000"&gt;ListBoxItem&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;!--CRLF--&gt;    &lt;span style="color: #606060" id="lnum4"&gt;   4:&lt;/span&gt;     &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;ListBoxItem&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;123&lt;span style="color: #0000ff"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000"&gt;ListBoxItem&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;!--CRLF--&gt;    &lt;span style="color: #606060" id="lnum5"&gt;   5:&lt;/span&gt; &lt;span style="color: #0000ff"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000"&gt;ListBox&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;!--CRLF--&gt;    &lt;span style="color: #606060" id="lnum6"&gt;   6:&lt;/span&gt; &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;Button&lt;/span&gt; &lt;span style="color: #ff0000"&gt;cm:Action&lt;/span&gt;.&lt;span style="color: #ff0000"&gt;Target&lt;/span&gt;&lt;span style="color: #0000ff"&gt;="{Binding ElementName=lstBox}"&lt;/span&gt; &lt;span style="color: #ff0000"&gt;Focusable&lt;/span&gt;&lt;span style="color: #0000ff"&gt;="False"&lt;/span&gt;&lt;!--CRLF--&gt;    &lt;span style="color: #606060" id="lnum7"&gt;   7:&lt;/span&gt;         &lt;span style="color: #ff0000"&gt;cm:Message&lt;/span&gt;.&lt;span style="color: #ff0000"&gt;Attach&lt;/span&gt;&lt;span style="color: #0000ff"&gt;="[Event Click] = [Action SelectAll]"&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;!--CRLF--&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;把Action的Target设置为ListBox，在Button点击时调用了ListBox的SelectAll方法。&lt;/p&gt;&lt;p&gt;这里的cm:Action.Target等同于DataContext={Binding &amp;#8230;}，在设置Target的同时，CM会同时设置控件的DataContext。有时并不需要设置控件的DataContext，Action提供了TargetWithoutContext来设置Target但并不同步控件的DataContext。&lt;/p&gt;&lt;p&gt;在Action的执行过程中，ActionMessage提供了ActionExecutionContext来提供执行上下文，这个上下文主要是用在另一个重要功能协同（Coroutine）上，这里不做详细介绍。&lt;/p&gt;&lt;h1 style="padding-bottom: 5px; background-color: gray; margin-top: 24px; padding-left: 5px; padding-right: 5px; margin-bottom: 12px; color: white; font-size: 26px; font-weight: normal; padding-top: 5px"&gt;总结&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;本文主要介绍了CM的Action机制，Action是CM框架设计中的亮点，简明，强大，围绕着Action，CM也设计出了其他一些功能，如Coroutine等，希望朋友们都能在CM开始的这个点上，把Action掌握好。&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;div&gt;&lt;span style="line-height: 25px; color: #333333"&gt;&lt;span style="line-height: 25px; background-color: #ffffff; font-family: georgia; color: #333333"&gt;&lt;span style="padding-bottom: 0px; line-height: 21px; margin: 0px; padding-left: 0px; padding-right: 0px; font-family: 宋体; color: black; font-size: 9pt; padding-top: 0px"&gt;作者：&lt;/span&gt;&lt;span style="padding-bottom: 0px; line-height: 21px; margin: 0px; padding-left: 0px; padding-right: 0px; font-family: verdana, sans-serif; color: black; font-size: 9pt; padding-top: 0px"&gt;&lt;a style="border-bottom: 1px dashed; padding-bottom: 0px; margin: 0px; outline-style: none; outline-color: ; padding-left: 0px; padding-right: 0px; color: #3d81ee; text-decoration: none; padding-top: 0px" href="http://www.cnblogs.com/Zhouyongh" target="_blank"&gt;&lt;span style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; font-family: 宋体; color: #ff6600; text-decoration: none; padding-top: 0px"&gt;周永恒&lt;/span&gt;&lt;/a&gt;         &lt;br style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px" /&gt;&lt;/span&gt;&lt;span style="padding-bottom: 0px; line-height: 21px; margin: 0px; padding-left: 0px; padding-right: 0px; font-family: 宋体; color: black; font-size: 9pt; padding-top: 0px"&gt;出处：&lt;/span&gt;&lt;span style="padding-bottom: 0px; line-height: 21px; margin: 0px; padding-left: 0px; padding-right: 0px; font-family: verdana, sans-serif; color: black; font-size: 9pt; padding-top: 0px"&gt;&lt;a style="border-bottom: 1px dashed; padding-bottom: 0px; margin: 0px; outline-style: none; outline-color: ; padding-left: 0px; padding-right: 0px; color: #3d81ee; text-decoration: none; padding-top: 0px" href="http://www.cnblogs.com/Zhouyongh" target="_blank"&gt;&lt;span style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; color: #ff6600; text-decoration: none; padding-top: 0px"&gt;http://www.cnblogs.com/Zhouyongh&lt;/span&gt;&lt;/a&gt;         &lt;br style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px" /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;p&gt;&lt;span style="line-height: 25px; font-family: 宋体; color: #333333; font-size: 12px" class="Apple-style-span"&gt;本文版权归作者和博客园共有，欢迎转载，但未经作者同意必须保留此段声明，且在文章页面明显位置给出原文连接，否则保留追究法律责任的权利。&lt;/span&gt;&lt;/p&gt;&lt;img src="http://www.cnblogs.com/Zhouyongh/aggbug/2018989.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/Zhouyongh/archive/2011/04/22/2018989.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/Zhouyongh/archive/2011/04/18/Caliburn.html</id><title type="text">解析Caliburn.Micro（一）</title><summary type="text">Caliburn是Codeplex上的一个开源框架，可用于WPF，Silverlight，WP7等，分享一下对于Caliburn.Micro的心得，希望能给朋友们带来点帮助。</summary><published>2011-04-18T03:35:00Z</published><updated>2011-04-18T03:35:00Z</updated><author><name>周永恒</name><uri>http://www.cnblogs.com/Zhouyongh/</uri></author><link rel="alternate" href="http://www.cnblogs.com/Zhouyongh/archive/2011/04/18/Caliburn.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/Zhouyongh/archive/2011/04/18/Caliburn.html"/><content type="html">&lt;h1 style="padding-bottom: 5px; background-color: gray; margin-top: 24px; padding-left: 5px; padding-right: 5px; margin-bottom: 12px; color: white; font-size: 26px; font-weight: normal; padding-top: 5px"&gt;简介&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;受朋友所邀，准备使用&lt;a href="http://caliburn.codeplex.com/"&gt;Caliburn&lt;/a&gt;框架设计项目，这两天研究了一下这个开源框架，分享一下。&lt;/p&gt;  &lt;p&gt;&lt;a href="http://caliburn.codeplex.com/"&gt;Caliburn&lt;/a&gt;是Rob Eisenberg在2009年提出的一个开源框架，可以应用于WPF，Silverlight，WP7等，框架基于MVVM模式，像它的名字一样，是企业级应用的一把利器。&lt;/p&gt;  &lt;p&gt;之前就听说过这个项目，下载过源码简单看了看，代码注释很用心，文档说明也很详尽。不过似乎有些想法太大，10多个工程，数万行代码，钦佩之余没有看得下去。&lt;/p&gt;  &lt;p&gt;显然作者也听取到了使用者的反馈，推出了&lt;a href="http://caliburnmicro.codeplex.com/"&gt;Caliburn.Micro&lt;/a&gt;项目，Micro顾名思义，是Caliburn项目的精简版。重构了Caliburn的代码，精简掉了一些不常用的功能，按作者的话来说：&lt;/p&gt;  &lt;blockquote style='border:2px solid #EFEFEF;color:#333333;padding:5px 10px;'&gt;   &lt;p&gt;My vision was to take 90% of Caliburn&amp;#8217;s features and squash them into 10% of the code.&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;非常给力的一句话，下面深入Caliburn.Micro，看看它的究竟。&lt;/p&gt;  &lt;h1 style="padding-bottom: 5px; background-color: gray; margin-top: 24px; padding-left: 5px; padding-right: 5px; margin-bottom: 12px; color: white; font-size: 26px; font-weight: normal; padding-top: 5px"&gt;亮点&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;在细谈&lt;a href="http://caliburnmicro.codeplex.com/"&gt;Caliburn.Micro&lt;/a&gt;（简称为CM）之前，先来看看它的亮点。&lt;/p&gt;  &lt;p&gt;基于WPF的框架有很多，&lt;a href="http://compositewpf.codeplex.com/"&gt;Prism&lt;/a&gt;，&lt;a href="http://waf.codeplex.com/"&gt;WAF&lt;/a&gt;等，每个框架都有自己侧重点，像Prism侧重于模块间的组合，WAF侧重于分层设计。通观CM的设计，它的一些想法如下：&lt;/p&gt;  &lt;ol&gt;   &lt;li&gt;ActionMessage，结合了Blend中的TriggerAction，可以把UI控件中的事件绑定到后台方法，类似于CallMethodAction。CM对ActionMessage进行了很多扩展，包括可以传入多个参数，参数支持绑定，可以通过CanExecute作执行前判断并设置控件的Enable等。 &lt;/li&gt;    &lt;li&gt;Conventions，协定，这个词听上去有点虚，其实就是智能匹配的意思。CM制定了一系列匹配的规则，比如说View和ViewModel之间的匹配，绑定时传入控件名可以找到控件，传入方法名可以绑定到方法等等。 &lt;/li&gt;    &lt;li&gt;Screen和Conductor，作为一个Presentation的框架，各个UI部件（Widget或者叫Pad）的管理是必不可少的。Screen就是用来表示UI部件的，它定义了一些列UI部件的生命期事件，比如Activated，DeActivated等。Conductor是用来管理Screen的，类似于传统的Controller，不同的Screen可以用一个Conductor来管理，Conductor也使用了策略模式允许更改对Screen的处理。 &lt;/li&gt;    &lt;li&gt;Coroutines，协同程序，定义了一组程序的执行，简化了异步编程。比如说在网络中下载图片并显示，通常来说需要显示BusyIndicator，后台线程去网络读取图片，读取成功后Invoke到UI线程，取消BusyIndicator，显示图片。CM提供了一个IResult接口，大大的简化了异步编程，结合ActionMessage，为AOP的扩展提供了可能。 &lt;/li&gt;    &lt;li&gt;配置性和扩展性，CM移除掉了原Caliburn的一些IOC实现，作为一个通用框架，最常用办法就是使用工厂模式结合配置文件提供可配置性，使用IOC来解耦组件间的依赖。CM默认是使用MEF来做IOC扩展的，你可以自定义Bootstrapper来使用你喜欢的IOC容器，如Unity等。 &lt;/li&gt;    &lt;li&gt;设计时支持（Design-time support），CM中的ActionMessage是继承自Blend中的TriggerAction的，也就是说可以在Blend编辑ActionMessage，大大方便了使用。 &lt;/li&gt; &lt;/ol&gt;  &lt;h1 style="padding-bottom: 5px; background-color: gray; margin-top: 24px; padding-left: 5px; padding-right: 5px; margin-bottom: 12px; color: white; font-size: 26px; font-weight: normal; padding-top: 5px"&gt;评价&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;CM符合我对于框架设计的期望，精简，特点鲜明，思路清晰，不过度设计，有很好的扩展性和可测试性。指望一个框架做所有事情是不现实的，用牛刀来杀鸡可能杀的爽快，不过学习的时间成本和后期维护成本都很高，目前对CM很有好感，打算下个项目基于CM搞一搞，如果朋友们有更好的经验和建议也希望多多交流。&lt;/p&gt;  &lt;p&gt;&amp;nbsp;&lt;/p&gt;  &lt;div&gt;&lt;span style="line-height: 25px; color: #333333"&gt;&lt;span style="line-height: 25px; background-color: #ffffff; font-family: georgia; color: #333333"&gt;&lt;span style="padding-bottom: 0px; line-height: 21px; margin: 0px; padding-left: 0px; padding-right: 0px; font-family: 宋体; color: black; font-size: 9pt; padding-top: 0px"&gt;作者：&lt;/span&gt;&lt;span style="padding-bottom: 0px; line-height: 21px; margin: 0px; padding-left: 0px; padding-right: 0px; font-family: verdana, sans-serif; color: black; font-size: 9pt; padding-top: 0px"&gt;&lt;a style="border-bottom: 1px dashed; padding-bottom: 0px; margin: 0px; outline-style: none; outline-color: ; padding-left: 0px; padding-right: 0px; color: #3d81ee; text-decoration: none; padding-top: 0px" href="http://www.cnblogs.com/Zhouyongh" target="_blank"&gt;&lt;span style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; font-family: 宋体; color: #ff6600; text-decoration: none; padding-top: 0px"&gt;周永恒&lt;/span&gt;&lt;/a&gt;           &lt;br style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px" /&gt;&lt;/span&gt;&lt;span style="padding-bottom: 0px; line-height: 21px; margin: 0px; padding-left: 0px; padding-right: 0px; font-family: 宋体; color: black; font-size: 9pt; padding-top: 0px"&gt;出处：&lt;/span&gt;&lt;span style="padding-bottom: 0px; line-height: 21px; margin: 0px; padding-left: 0px; padding-right: 0px; font-family: verdana, sans-serif; color: black; font-size: 9pt; padding-top: 0px"&gt;&lt;a style="border-bottom: 1px dashed; padding-bottom: 0px; margin: 0px; outline-style: none; outline-color: ; padding-left: 0px; padding-right: 0px; color: #3d81ee; text-decoration: none; padding-top: 0px" href="http://www.cnblogs.com/Zhouyongh" target="_blank"&gt;&lt;span style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; color: #ff6600; text-decoration: none; padding-top: 0px"&gt;http://www.cnblogs.com/Zhouyongh&lt;/span&gt;&lt;/a&gt;           &lt;br style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px" /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;  &lt;p&gt;&lt;span style="line-height: 25px; font-family: 宋体; color: #333333; font-size: 12px" class="Apple-style-span"&gt;本文版权归作者和博客园共有，欢迎转载，但未经作者同意必须保留此段声明，且在文章页面明显位置给出原文连接，否则保留追究法律责任的权利。&lt;/span&gt;&lt;/p&gt;&lt;img src="http://www.cnblogs.com/Zhouyongh/aggbug/2018908.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/Zhouyongh/archive/2011/04/18/Caliburn.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/Zhouyongh/archive/2011/03/09/1977768.html</id><title type="text">WPF企业应用--自实现Binding，可用于WinForm，Web等</title><summary type="text">开始写这个新系列，这些年用WPF做了很多项目，杂七杂八的东西写了不少，略略总结下，也希望能给朋友们带来点帮助。本篇文章主要是自实现了一个BindingEngine，可以在WPF，WinForm，Web等各个情景中使用。</summary><published>2011-03-08T17:29:00Z</published><updated>2011-03-08T17:29:00Z</updated><author><name>周永恒</name><uri>http://www.cnblogs.com/Zhouyongh/</uri></author><link rel="alternate" href="http://www.cnblogs.com/Zhouyongh/archive/2011/03/09/1977768.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/Zhouyongh/archive/2011/03/09/1977768.html"/><content type="html">&lt;h1 style="padding-bottom: 5px; background-color: gray; margin-top: 24px; padding-left: 5px; padding-right: 5px; margin-bottom: 12px; color: white; font-size: 26px; font-weight: normal; padding-top: 5px"&gt;前言&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;开始写这个新系列，这些年用WPF做了很多项目，杂七杂八的东西写了不少，略略总结下，也希望能给朋友们带来点帮助。&lt;/p&gt;  &lt;p&gt;本篇文章主要是自实现了一个BindingEngine，可以在WPF，WinForm，Web等各个情景中使用。&lt;/p&gt;  &lt;h1 style="padding-bottom: 5px; background-color: gray; margin-top: 24px; padding-left: 5px; padding-right: 5px; margin-bottom: 12px; color: white; font-size: 26px; font-weight: normal; padding-top: 5px"&gt;引子&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;按照惯例，先找一个插入点，从之讲起。&lt;/p&gt;  &lt;p&gt;既然是企业应用，先来说说为什么要写这个BindingEngine。&lt;/p&gt;  &lt;p&gt;项目背景是一个机械的配置文件编辑器，大概有200多个机械，每个机械200多个参数，要支持增/删/改，版本控制，Undo/Redo等一系列操作。使用WPF开发界面，开发模式采用MVVM，控件选取了DataGrid。为了提高性能，使用了Virtualizing等一系列方案优化。项目原型开发后，面对如此大数量的Cell，DataGrid的表现十分令人伤心，无论是性能还是内存占用量，都有很长的路要走。&lt;/p&gt;  &lt;p&gt;一条路走到黑是不行的，把DataGrid更换为&lt;a href="http://sourcegrid.codeplex.com/"&gt;SourceGrid&lt;/a&gt;，SourceGrid是Codeplex上的一个开源C#表格实现，自测量和绘制内部的Cell，思路和实现很赞。更换控件后，一切顺利，但SourceGrid对绑定支持的不够。MVVM模式，VM（ViewModel）是PM（PresentationModel）的一个演化，由于采用了数据绑定和Behavior，View和PM之间可以更充分解耦，PM中Presentation的含义是其中要保存所有可能被用户修改的View的状态。修改了PM中View的状态后，通过数据绑定，View应该自动刷新，但SourceGrid不是基于WPF的，要实现Visible，Filter，换肤等功能PM需要持有View的引用或者通过MVP模式抽象出View的接口，无论哪种模式都要修改原有的设计，于是就萌生出了自实现一个BindingEngine 的想法。&lt;/p&gt;  &lt;h1 style="padding-bottom: 5px; background-color: gray; margin-top: 24px; padding-left: 5px; padding-right: 5px; margin-bottom: 12px; color: white; font-size: 26px; font-weight: normal; padding-top: 5px"&gt;什么是Binding？&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;在实现一个BindingEngine之前，先来看一下，什么是Binding？&lt;/p&gt;  &lt;p&gt;Binding（绑定），是在.net 2.0之后被提出的，Binding大体分两类，一类是List控件绑定到List上，根据List的改变来增减List控件的Item。另一类是把单一View绑定到Model上，根据Model的属性变化来更改View的状态。&lt;/p&gt;  &lt;p&gt;Binding这个概念简单易懂，使用起来也很方便，一提出就受到了热捧，在WPF/Silverlight中更是大行其道，基本所有介绍WPF的资料中都会把Binding拿出来炫耀一番。本文不是介绍如何使用WPF/Silverlight中Binding的，那么Binding的原理是什么呢？&lt;/p&gt;  &lt;h1 style="padding-bottom: 5px; background-color: gray; margin-top: 24px; padding-left: 5px; padding-right: 5px; margin-bottom: 12px; color: white; font-size: 26px; font-weight: normal; padding-top: 5px"&gt;Binding的原理&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;一个最简单的Binding就是把A的属性绑定到B的属性上，当B的属性变化时，A的属性可以自动更新。这个Binding分两层含义：&lt;/p&gt;  &lt;ol&gt;   &lt;li&gt;A需要监视B属性的变化，当B属性变化时A得到通知。 &lt;/li&gt;    &lt;li&gt;当收到变化通知时，A要根据B的属性新值来设置自己的属性值。 &lt;/li&gt; &lt;/ol&gt;  &lt;p&gt;关于监视B属性变化，这是一个经典的Observer模式，在.net中用&lt;font color="#9b00d3"&gt;event &lt;/font&gt;来表示，如：&lt;/p&gt;  &lt;div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 100%; padding-right: 4px; font-family: 'Courier New', courier, monospace; direction: ltr; height: 90px; max-height: 200px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"&gt;   &lt;div style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; height: 56px; color: black; border-right-style: none; font-size: 8pt; padding-top: 0px" id="codeSnippet"&gt;     &lt;span style="color: #606060" id="lnum1"&gt;   1:&lt;/span&gt; b.PropertyChanged += a.HandlePropertyChanged;&lt;!--CRLF--&gt;    &lt;span style="color: #606060" id="lnum2"&gt;   2:&lt;/span&gt; &lt;span style="color: #0000ff"&gt;void&lt;/span&gt; HandlePropertyChanged()&lt;!--CRLF--&gt;    &lt;span style="color: #606060" id="lnum3"&gt;   3:&lt;/span&gt; {&lt;!--CRLF--&gt;    &lt;span style="color: #606060" id="lnum4"&gt;   4:&lt;/span&gt;     a.Prop = b.Prop;&lt;!--CRLF--&gt;    &lt;span style="color: #606060" id="lnum5"&gt;   5:&lt;/span&gt; }&lt;!--CRLF--&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;关于PropertyChange事件，.net在System.ComponentModel里提供了INotifyPropertyChanged接口，里面定义了&lt;font color="#9b00d3"&gt;event &lt;/font&gt;PropertyChangedEventHandler PropertyChanged。通常可被用于数据绑定的Model类都要实现INotifyPropertyChanged接口，在属性变化时raise这个PropertyChanged事件。&lt;/p&gt;&lt;h1 style="padding-bottom: 5px; background-color: gray; margin-top: 24px; padding-left: 5px; padding-right: 5px; margin-bottom: 12px; color: white; font-size: 26px; font-weight: normal; padding-top: 5px"&gt;Binding的亮点&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;在WPF中，Binding无处不在，关于Binding的漂亮用法有很多，其主要的设计亮点有二：&lt;/p&gt;&lt;ol&gt;  &lt;li&gt;Weak Event模式 &lt;/li&gt;  &lt;li&gt;Converter &lt;/li&gt;&lt;/ol&gt;&lt;p&gt;监听B的属性变化，A需要注册B的PropertyChanged事件，.net中事件是强引用，一旦A注册了B的事件，B就持有了一个A的引用。也就是说，如果A不注销B的事件，即使A已经空置，如果B对象存活，垃圾回收器仍不会回收A的内存，在使用中就造成了A的内存泄露。在Binding的使用过程中，可能会出现多级绑定，A-&amp;gt;B-&amp;gt;C，一个对象也可能绑定多个对象，在对象空置时注销绑定的监听事件是不太现实的，实现起来太过繁琐。这里就期望能有弱事件（Weak Event）模式，即A监听了B的事件后，B不会阻止A的垃圾回收。&lt;/p&gt;&lt;p&gt;直接把A的属性绑定到B的属性上有时也是不太友好的，比如B的属性是string，A的属性是DateTime，在绑定的过程中需要做一定的转换（Convert）。WPF/Silverlight中的Converter是很不错的想法，可以自定义一些转换，在属性间做一些转换工作。&lt;/p&gt;&lt;h1 style="padding-bottom: 5px; background-color: gray; margin-top: 24px; padding-left: 5px; padding-right: 5px; margin-bottom: 12px; color: white; font-size: 26px; font-weight: normal; padding-top: 5px"&gt;设计&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;开始设计实现BindingEngine，首先来解决弱事件的问题。&lt;/p&gt;&lt;p&gt;在.net中，可以使用WeakReference（弱引用）来监视对象，WeakReference不会阻止对象的垃圾回收。在实际使用中，A注册B的事件后，B持有了A的引用，B对象会阻止A的垃圾回收。直接把B对象变成弱引用对象是不现实的，但可以引入弱引用对象C，让B持有C的引用，C持有A的引用。这样即使没有注销事件监视，C对象仍持有A的引用，但是C对象是弱引用对象，不会阻止A的垃圾回收。&lt;/p&gt;&lt;p&gt;用一副图表示：&lt;/p&gt;&lt;p&gt;&lt;a href="http://images.cnblogs.com/cnblogs_com/Zhouyongh/201103/201103090043218451.png"&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://images.cnblogs.com/cnblogs_com/Zhouyongh/201103/201103090043229465.png" width="554" height="224" /&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;把用来作为中间传递的C类命名为WeakSource，它的设计如下：&lt;/p&gt;&lt;p&gt;&lt;a href="http://images.cnblogs.com/cnblogs_com/Zhouyongh/201103/201103090043249790.png"&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://images.cnblogs.com/cnblogs_com/Zhouyongh/201103/201103090043252100.png" width="907" height="285" /&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;WeakSource用来隔离A对象，为了内存考虑，它和A对象间是一一对应关系。这样，在监听B的PropertyChanged事件时，原有的b.ProppertyChanged += a.HandlePropertyChanged就变成了b.PropertyChanged += weakSource.HandlePropertyChanged。WeakSource提供了两个静态方法Register和UnRegister来创建和销毁WeakSource，其中的第一个参数object Source就是WeakSource需要封装的A对象。&lt;/p&gt;&lt;p&gt;Register的第二个参数INotifyPropertyChanged target，就是需要监听的B对象，最后一个参数targetProp是需要监听B对象的属性名。当B的属性值发生变化时，WeakSource会得到通知，为了完成绑定，WeakSource需要把内部封装的A对象对应的属性值设置为B对象绑定属性的新值。&lt;/p&gt;&lt;h1 style="padding-bottom: 5px; background-color: gray; margin-top: 24px; padding-left: 5px; padding-right: 5px; margin-bottom: 12px; color: white; font-size: 26px; font-weight: normal; padding-top: 5px"&gt;绑定值&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;当B属性绑定值发生变化时，完成绑定需要设置两步，一，取得B属性的新值。二，把这个新值设置到A属性上去。&lt;/p&gt;&lt;p&gt;最简单的办法可以用反射完成这两步操作，为了编写简单，使用了Expression Tree来构建这个取值赋值操作：&lt;/p&gt;&lt;div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 100%; padding-right: 4px; font-family: 'Courier New', courier, monospace; direction: ltr; height: 205px; max-height: 260px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"&gt;  &lt;div style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; height: 187px; color: black; border-right-style: none; font-size: 8pt; padding-top: 0px" id="codeSnippet"&gt;    &lt;span style="color: #606060" id="lnum1"&gt;   1:&lt;/span&gt; &lt;span style="color: #008000"&gt;//Set Property&lt;/span&gt;&lt;!--CRLF--&gt;    &lt;span style="color: #606060" id="lnum2"&gt;   2:&lt;/span&gt; var prop = entry.SourceType.GetProperty(entry.SourceProp);&lt;!--CRLF--&gt;    &lt;span style="color: #606060" id="lnum3"&gt;   3:&lt;/span&gt; var paraSource = Expression.Parameter(entry.SourceType, &lt;span style="color: #006080"&gt;"source"&lt;/span&gt;);&lt;!--CRLF--&gt;    &lt;span style="color: #606060" id="lnum4"&gt;   4:&lt;/span&gt;&amp;nbsp; &lt;!--CRLF--&gt;    &lt;span style="color: #606060" id="lnum5"&gt;   5:&lt;/span&gt; &lt;span style="color: #008000"&gt;//Get Property&lt;/span&gt;&lt;!--CRLF--&gt;    &lt;span style="color: #606060" id="lnum6"&gt;   6:&lt;/span&gt; var targetProperty = entry.TargetType.GetProperty(entry.TargetProp);&lt;!--CRLF--&gt;    &lt;span style="color: #606060" id="lnum7"&gt;   7:&lt;/span&gt; var paraTarget = Expression.Parameter(entry.TargetType, &lt;span style="color: #006080"&gt;"target"&lt;/span&gt;);&lt;!--CRLF--&gt;    &lt;span style="color: #606060" id="lnum8"&gt;   8:&lt;/span&gt; var getter = Expression.Property(paraTarget, targetProperty);&lt;!--CRLF--&gt;    &lt;span style="color: #606060" id="lnum9"&gt;   9:&lt;/span&gt;&amp;nbsp; &lt;!--CRLF--&gt;    &lt;span style="color: #606060" id="lnum10"&gt;  10:&lt;/span&gt; &lt;span style="color: #008000"&gt;//Combine&lt;/span&gt;&lt;!--CRLF--&gt;    &lt;span style="color: #606060" id="lnum11"&gt;  11:&lt;/span&gt; var boy = Expression.Call(paraSource, prop.GetSetMethod(), getter);&lt;!--CRLF--&gt;    &lt;span style="color: #606060" id="lnum12"&gt;  12:&lt;/span&gt; Delegate action = Expression.Lambda(boy, paraSource, paraTarget).Compile();&lt;!--CRLF--&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;在WeakSource的Register方法中传入的第三个参数就是这个Delegate，当绑定的B属性值发生变化是，调用Delegate的DynamicInvoke方法即可完成更新值操作。&lt;/p&gt;&lt;div id="codeSnippetWrapper"&gt;  &lt;div id="codeSnippetWrapper" class="csharpcode-wrapper"&gt;    &lt;div id="codeSnippet" class="csharpcode"&gt;      &lt;div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 100%; padding-right: 4px; font-family: 'Courier New', courier, monospace; direction: ltr; height: 32px; max-height: 260px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"&gt;        &lt;div style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; padding-top: 0px" id="codeSnippet"&gt;          &lt;span style="color: #606060" id="lnum1"&gt;   1:&lt;/span&gt; action.DynamicInvoke(&lt;font color="#0000ff"&gt;source&lt;/font&gt;, target)&lt;!--CRLF--&gt;&lt;/div&gt;      &lt;/div&gt;&lt;!--CRLF--&gt;&lt;/div&gt;  &lt;/div&gt;&lt;/div&gt;&lt;h1 style="padding-bottom: 5px; background-color: gray; margin-top: 24px; padding-left: 5px; padding-right: 5px; margin-bottom: 12px; color: white; font-size: 26px; font-weight: normal; padding-top: 5px"&gt;Converter&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;顺水推舟，加上对Converter的支持，定义IDataConverter接口，如下：&lt;/p&gt;&lt;div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 100%; padding-right: 4px; font-family: 'Courier New', courier, monospace; direction: ltr; height: 74px; max-height: 260px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"&gt;  &lt;div style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; height: 60px; color: black; border-right-style: none; font-size: 8pt; padding-top: 0px" id="codeSnippet"&gt;    &lt;span style="color: #606060" id="lnum1"&gt;   1:&lt;/span&gt; &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;interface&lt;/span&gt; IDataConverter&lt;!--CRLF--&gt;    &lt;span style="color: #606060" id="lnum2"&gt;   2:&lt;/span&gt; {&lt;!--CRLF--&gt;    &lt;span style="color: #606060" id="lnum3"&gt;   3:&lt;/span&gt;     &lt;span style="color: #0000ff"&gt;object&lt;/span&gt; Convert(&lt;span style="color: #0000ff"&gt;object&lt;/span&gt; &lt;span style="color: #0000ff"&gt;value&lt;/span&gt;, &lt;span style="color: #0000ff"&gt;object&lt;/span&gt; parameter);&lt;!--CRLF--&gt;    &lt;span style="color: #606060" id="lnum4"&gt;   4:&lt;/span&gt; }&lt;!--CRLF--&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;修改Register接口：&lt;/p&gt;&lt;div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 100%; padding-right: 4px; font-family: 'Courier New', courier, monospace; direction: ltr; height: 44px; max-height: 260px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"&gt;  &lt;div style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; height: 29px; color: black; border-right-style: none; font-size: 8pt; padding-top: 0px" id="codeSnippet"&gt;    &lt;span style="color: #606060" id="lnum1"&gt;   1:&lt;/span&gt; &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;static&lt;/span&gt; WeakSource Register(Object source, INotifyPropertyChanged target, Delegate action, &lt;span style="color: #0000ff"&gt;string&lt;/span&gt; targetProp, &lt;!--CRLF--&gt;    &lt;span style="color: #606060" id="lnum2"&gt;   2:&lt;/span&gt;                                 IDataConverter converter = &lt;span style="color: #0000ff"&gt;null&lt;/span&gt;, &lt;span style="color: #0000ff"&gt;object&lt;/span&gt; parameter = &lt;span style="color: #0000ff"&gt;null&lt;/span&gt;)&lt;!--CRLF--&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;为了重用构建出的Expression Tree，缓存了构建出的Delegate，创建结构体WeakEntry作为索引&lt;/p&gt;&lt;div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 100%; padding-right: 4px; font-family: 'Courier New', courier, monospace; direction: ltr; max-height: 260px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"&gt;  &lt;div style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; height: 110px; color: black; border-right-style: none; font-size: 8pt; padding-top: 0px" id="codeSnippet"&gt;    &lt;span style="color: #606060" id="lnum1"&gt;   1:&lt;/span&gt; &lt;span style="color: #0000ff"&gt;private&lt;/span&gt; &lt;span style="color: #0000ff"&gt;struct&lt;/span&gt; WeakEntry&lt;!--CRLF--&gt;    &lt;span style="color: #606060" id="lnum2"&gt;   2:&lt;/span&gt; {&lt;!--CRLF--&gt;    &lt;span style="color: #606060" id="lnum3"&gt;   3:&lt;/span&gt;     &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; Type SourceType;&lt;!--CRLF--&gt;    &lt;span style="color: #606060" id="lnum4"&gt;   4:&lt;/span&gt;     &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; Type TargetType;&lt;!--CRLF--&gt;    &lt;span style="color: #606060" id="lnum5"&gt;   5:&lt;/span&gt;     &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;string&lt;/span&gt; SourceProp;&lt;!--CRLF--&gt;    &lt;span style="color: #606060" id="lnum6"&gt;   6:&lt;/span&gt;     &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;string&lt;/span&gt; TargetProp;&lt;!--CRLF--&gt;    &lt;span style="color: #606060" id="lnum7"&gt;   7:&lt;/span&gt; }&lt;!--CRLF--&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;对应修改的Expression Tree如下：&lt;/p&gt;&lt;div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 100%; padding-right: 4px; font-family: 'Courier New', courier, monospace; direction: ltr; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"&gt;  &lt;div style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; height: 381px; color: black; border-right-style: none; font-size: 8pt; padding-top: 0px" id="codeSnippet"&gt;    &lt;span style="color: #606060" id="lnum1"&gt;   1:&lt;/span&gt; &lt;span style="color: #008000"&gt;//Set Property&lt;/span&gt;&lt;!--CRLF--&gt;    &lt;span style="color: #606060" id="lnum2"&gt;   2:&lt;/span&gt; var prop = entry.SourceType.GetProperty(entry.SourceProp);&lt;!--CRLF--&gt;    &lt;span style="color: #606060" id="lnum3"&gt;   3:&lt;/span&gt; var paraObj = Expression.Parameter(entry.SourceType);&lt;!--CRLF--&gt;    &lt;span style="color: #606060" id="lnum4"&gt;   4:&lt;/span&gt;&amp;nbsp; &lt;!--CRLF--&gt;    &lt;span style="color: #606060" id="lnum5"&gt;   5:&lt;/span&gt; &lt;span style="color: #008000"&gt;//Get Property&lt;/span&gt;&lt;!--CRLF--&gt;    &lt;span style="color: #606060" id="lnum6"&gt;   6:&lt;/span&gt; var targetProperty = entry.TargetType.GetProperty(entry.TargetProp);&lt;!--CRLF--&gt;    &lt;span style="color: #606060" id="lnum7"&gt;   7:&lt;/span&gt; var paraTarget = Expression.Parameter(entry.TargetType);&lt;!--CRLF--&gt;    &lt;span style="color: #606060" id="lnum8"&gt;   8:&lt;/span&gt; var getter = Expression.Property(paraTarget, targetProperty);&lt;!--CRLF--&gt;    &lt;span style="color: #606060" id="lnum9"&gt;   9:&lt;/span&gt;&amp;nbsp; &lt;!--CRLF--&gt;    &lt;span style="color: #606060" id="lnum10"&gt;  10:&lt;/span&gt; &lt;span style="color: #008000"&gt;//Combine&lt;/span&gt;&lt;!--CRLF--&gt;    &lt;span style="color: #606060" id="lnum11"&gt;  11:&lt;/span&gt; var paraConvert = Expression.Variable(&lt;span style="color: #0000ff"&gt;typeof&lt;/span&gt;(IDataConverter));&lt;!--CRLF--&gt;    &lt;span style="color: #606060" id="lnum12"&gt;  12:&lt;/span&gt; var paraParameter = Expression.Variable(&lt;span style="color: #0000ff"&gt;typeof&lt;/span&gt;(&lt;span style="color: #0000ff"&gt;object&lt;/span&gt;));&lt;!--CRLF--&gt;    &lt;span style="color: #606060" id="lnum13"&gt;  13:&lt;/span&gt;&amp;nbsp; &lt;!--CRLF--&gt;    &lt;span style="color: #606060" id="lnum14"&gt;  14:&lt;/span&gt; var boy = Expression.IfThenElse(&lt;!--CRLF--&gt;    &lt;span style="color: #606060" id="lnum15"&gt;  15:&lt;/span&gt;         Expression.NotEqual(paraConvert, Expression.Constant(&lt;span style="color: #0000ff"&gt;null&lt;/span&gt;)),&lt;!--CRLF--&gt;    &lt;span style="color: #606060" id="lnum16"&gt;  16:&lt;/span&gt;         Expression.Call(paraObj, prop.GetSetMethod(), Expression.Convert(Expression.Call(paraConvert, &lt;span style="color: #0000ff"&gt;typeof&lt;/span&gt;(IDataConverter).GetMethod(&lt;span style="color: #006080"&gt;"Convert"&lt;/span&gt;),&lt;!--CRLF--&gt;    &lt;span style="color: #606060" id="lnum17"&gt;  17:&lt;/span&gt;                             Expression.Convert(getter, &lt;span style="color: #0000ff"&gt;typeof&lt;/span&gt;(&lt;span style="color: #0000ff"&gt;object&lt;/span&gt;)), Expression.Convert(paraParameter, &lt;span style="color: #0000ff"&gt;typeof&lt;/span&gt;(&lt;span style="color: #0000ff"&gt;object&lt;/span&gt;))), prop.PropertyType)),&lt;!--CRLF--&gt;    &lt;span style="color: #606060" id="lnum18"&gt;  18:&lt;/span&gt;         Expression.IfThenElse(&lt;!--CRLF--&gt;    &lt;span style="color: #606060" id="lnum19"&gt;  19:&lt;/span&gt;             Expression.Equal(Expression.Constant(prop.PropertyType, &lt;span style="color: #0000ff"&gt;typeof&lt;/span&gt;(Type)), Expression.Constant(getter.Type, &lt;span style="color: #0000ff"&gt;typeof&lt;/span&gt;(Type))),&lt;!--CRLF--&gt;    &lt;span style="color: #606060" id="lnum20"&gt;  20:&lt;/span&gt;             Expression.Call(paraObj, prop.GetSetMethod(), Expression.Convert(Expression.Convert(getter, &lt;span style="color: #0000ff"&gt;typeof&lt;/span&gt;(&lt;span style="color: #0000ff"&gt;object&lt;/span&gt;)), prop.PropertyType)),&lt;!--CRLF--&gt;    &lt;span style="color: #606060" id="lnum21"&gt;  21:&lt;/span&gt;             Expression.Throw(Expression.Constant(&lt;span style="color: #0000ff"&gt;new&lt;/span&gt; InvalidOperationException(&lt;!--CRLF--&gt;    &lt;span style="color: #606060" id="lnum22"&gt;  22:&lt;/span&gt;                 &lt;span style="color: #006080"&gt;"The property type between binding source and target does not match, please use IDataConverter to do custom convert."&lt;/span&gt;)))));&lt;!--CRLF--&gt;    &lt;span style="color: #606060" id="lnum23"&gt;  23:&lt;/span&gt;&amp;nbsp; &lt;!--CRLF--&gt;    &lt;span style="color: #606060" id="lnum24"&gt;  24:&lt;/span&gt; Delegate action = Expression.Lambda(boy, paraObj, paraTarget, paraConvert, paraParameter).Compile();&lt;!--CRLF--&gt;&lt;/div&gt;&lt;/div&gt;&lt;h1 style="padding-bottom: 5px; background-color: gray; margin-top: 24px; padding-left: 5px; padding-right: 5px; margin-bottom: 12px; color: white; font-size: 26px; font-weight: normal; padding-top: 5px"&gt;使用Binding&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;创建类BindingEngine，封装Binding的操作，&lt;/p&gt;&lt;div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 100%; padding-right: 4px; font-family: 'Courier New', courier, monospace; direction: ltr; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"&gt;  &lt;div style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; height: 140px; color: black; border-right-style: none; font-size: 8pt; padding-top: 0px" id="codeSnippet"&gt;    &lt;span style="color: #606060" id="lnum1"&gt;   1:&lt;/span&gt; &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;class&lt;/span&gt; BindingEngine&lt;!--CRLF--&gt;    &lt;span style="color: #606060" id="lnum2"&gt;   2:&lt;/span&gt; {&lt;!--CRLF--&gt;    &lt;span style="color: #606060" id="lnum3"&gt;   3:&lt;/span&gt;     &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;static&lt;/span&gt; &lt;span style="color: #0000ff"&gt;void&lt;/span&gt; SetPropertyBinding(Object source, INotifyPropertyChanged target, &lt;span style="color: #0000ff"&gt;string&lt;/span&gt; sourceProp, &lt;span style="color: #0000ff"&gt;string&lt;/span&gt; targetProp, &lt;!--CRLF--&gt;    &lt;span style="color: #606060" id="lnum4"&gt;   4:&lt;/span&gt;                                             IDataConverter converter = &lt;span style="color: #0000ff"&gt;null&lt;/span&gt;, &lt;span style="color: #0000ff"&gt;object&lt;/span&gt; parameter = &lt;span style="color: #0000ff"&gt;null&lt;/span&gt;)&lt;!--CRLF--&gt;    &lt;span style="color: #606060" id="lnum5"&gt;   5:&lt;/span&gt;     {}&lt;!--CRLF--&gt;    &lt;span style="color: #606060" id="lnum6"&gt;   6:&lt;/span&gt;&amp;nbsp; &lt;!--CRLF--&gt;    &lt;span style="color: #606060" id="lnum7"&gt;   7:&lt;/span&gt;     &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;static&lt;/span&gt; &lt;span style="color: #0000ff"&gt;void&lt;/span&gt; ClearPropertyBinding(Object source, INotifyPropertyChanged target, &lt;span style="color: #0000ff"&gt;string&lt;/span&gt; sourceProp, &lt;span style="color: #0000ff"&gt;string&lt;/span&gt; targetProp)&lt;!--CRLF--&gt;    &lt;span style="color: #606060" id="lnum8"&gt;   8:&lt;/span&gt;     {}&lt;!--CRLF--&gt;    &lt;span style="color: #606060" id="lnum9"&gt;   9:&lt;/span&gt; }&lt;!--CRLF--&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;创建测试类View和ViewModel，以及TextConverter&lt;/p&gt;&lt;div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 100%; padding-right: 4px; font-family: 'Courier New', courier, monospace; direction: ltr; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"&gt;  &lt;div style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; height: 717px; color: black; border-right-style: none; font-size: 8pt; padding-top: 0px" id="codeSnippet"&gt;    &lt;span style="color: #606060" id="lnum1"&gt;   1:&lt;/span&gt; &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;class&lt;/span&gt; View&lt;!--CRLF--&gt;    &lt;span style="color: #606060" id="lnum2"&gt;   2:&lt;/span&gt; {&lt;!--CRLF--&gt;    &lt;span style="color: #606060" id="lnum3"&gt;   3:&lt;/span&gt;     &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;string&lt;/span&gt; Text { get; set; }&lt;!--CRLF--&gt;    &lt;span style="color: #606060" id="lnum4"&gt;   4:&lt;/span&gt;     &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;int&lt;/span&gt; Value { get; set; }&lt;!--CRLF--&gt;    &lt;span style="color: #606060" id="lnum5"&gt;   5:&lt;/span&gt; }&lt;!--CRLF--&gt;    &lt;span style="color: #606060" id="lnum6"&gt;   6:&lt;/span&gt;&amp;nbsp; &lt;!--CRLF--&gt;    &lt;span style="color: #606060" id="lnum7"&gt;   7:&lt;/span&gt; &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;class&lt;/span&gt; ViewModel : INotifyPropertyChanged&lt;!--CRLF--&gt;    &lt;span style="color: #606060" id="lnum8"&gt;   8:&lt;/span&gt; {&lt;!--CRLF--&gt;    &lt;span style="color: #606060" id="lnum9"&gt;   9:&lt;/span&gt;     &lt;span style="color: #0000ff"&gt;private&lt;/span&gt; &lt;span style="color: #0000ff"&gt;int&lt;/span&gt; _Value = 0;&lt;!--CRLF--&gt;    &lt;span style="color: #606060" id="lnum10"&gt;  10:&lt;/span&gt;     &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;int&lt;/span&gt; Value&lt;!--CRLF--&gt;    &lt;span style="color: #606060" id="lnum11"&gt;  11:&lt;/span&gt;     {&lt;!--CRLF--&gt;    &lt;span style="color: #606060" id="lnum12"&gt;  12:&lt;/span&gt;         get&lt;!--CRLF--&gt;    &lt;span style="color: #606060" id="lnum13"&gt;  13:&lt;/span&gt;         {&lt;!--CRLF--&gt;    &lt;span style="color: #606060" id="lnum14"&gt;  14:&lt;/span&gt;             &lt;span style="color: #0000ff"&gt;return&lt;/span&gt; _Value;&lt;!--CRLF--&gt;    &lt;span style="color: #606060" id="lnum15"&gt;  15:&lt;/span&gt;         }&lt;!--CRLF--&gt;    &lt;span style="color: #606060" id="lnum16"&gt;  16:&lt;/span&gt;         set&lt;!--CRLF--&gt;    &lt;span style="color: #606060" id="lnum17"&gt;  17:&lt;/span&gt;         {&lt;!--CRLF--&gt;    &lt;span style="color: #606060" id="lnum18"&gt;  18:&lt;/span&gt;             _Value = &lt;span style="color: #0000ff"&gt;value&lt;/span&gt;;&lt;!--CRLF--&gt;    &lt;span style="color: #606060" id="lnum19"&gt;  19:&lt;/span&gt;             NotifyPropertyChanged(&lt;span style="color: #006080"&gt;"Value"&lt;/span&gt;);&lt;!--CRLF--&gt;    &lt;span style="color: #606060" id="lnum20"&gt;  20:&lt;/span&gt;         }&lt;!--CRLF--&gt;    &lt;span style="color: #606060" id="lnum21"&gt;  21:&lt;/span&gt;     }&lt;!--CRLF--&gt;    &lt;span style="color: #606060" id="lnum22"&gt;  22:&lt;/span&gt;&amp;nbsp; &lt;!--CRLF--&gt;    &lt;span style="color: #606060" id="lnum23"&gt;  23:&lt;/span&gt;     &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;event&lt;/span&gt; PropertyChangedEventHandler PropertyChanged;&lt;!--CRLF--&gt;    &lt;span style="color: #606060" id="lnum24"&gt;  24:&lt;/span&gt;&amp;nbsp; &lt;!--CRLF--&gt;    &lt;span style="color: #606060" id="lnum25"&gt;  25:&lt;/span&gt;     &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;void&lt;/span&gt; NotifyPropertyChanged(&lt;span style="color: #0000ff"&gt;string&lt;/span&gt; prop)&lt;!--CRLF--&gt;    &lt;span style="color: #606060" id="lnum26"&gt;  26:&lt;/span&gt;     {&lt;!--CRLF--&gt;    &lt;span style="color: #606060" id="lnum27"&gt;  27:&lt;/span&gt;         &lt;span style="color: #0000ff"&gt;if&lt;/span&gt; (PropertyChanged != &lt;span style="color: #0000ff"&gt;null&lt;/span&gt;)&lt;!--CRLF--&gt;    &lt;span style="color: #606060" id="lnum28"&gt;  28:&lt;/span&gt;         {&lt;!--CRLF--&gt;    &lt;span style="color: #606060" id="lnum29"&gt;  29:&lt;/span&gt;             PropertyChanged(&lt;span style="color: #0000ff"&gt;this&lt;/span&gt;, &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; PropertyChangedEventArgs(prop));&lt;!--CRLF--&gt;    &lt;span style="color: #606060" id="lnum30"&gt;  30:&lt;/span&gt;         }&lt;!--CRLF--&gt;    &lt;span style="color: #606060" id="lnum31"&gt;  31:&lt;/span&gt;     }&lt;!--CRLF--&gt;    &lt;span style="color: #606060" id="lnum32"&gt;  32:&lt;/span&gt; }&lt;!--CRLF--&gt;    &lt;span style="color: #606060" id="lnum33"&gt;  33:&lt;/span&gt;&amp;nbsp; &lt;!--CRLF--&gt;    &lt;span style="color: #606060" id="lnum34"&gt;  34:&lt;/span&gt; &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;class&lt;/span&gt; TextConverter : IDataConverter&lt;!--CRLF--&gt;    &lt;span style="color: #606060" id="lnum35"&gt;  35:&lt;/span&gt; {&lt;!--CRLF--&gt;    &lt;span style="color: #606060" id="lnum36"&gt;  36:&lt;/span&gt;     &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;object&lt;/span&gt; Convert(&lt;span style="color: #0000ff"&gt;object&lt;/span&gt; &lt;span style="color: #0000ff"&gt;value&lt;/span&gt;, &lt;span style="color: #0000ff"&gt;object&lt;/span&gt; parameter)&lt;!--CRLF--&gt;    &lt;span style="color: #606060" id="lnum37"&gt;  37:&lt;/span&gt;     {&lt;!--CRLF--&gt;    &lt;span style="color: #606060" id="lnum38"&gt;  38:&lt;/span&gt;         &lt;span style="color: #0000ff"&gt;int&lt;/span&gt; v = System.Convert.ToInt32(&lt;span style="color: #0000ff"&gt;value&lt;/span&gt;);&lt;!--CRLF--&gt;    &lt;span style="color: #606060" id="lnum39"&gt;  39:&lt;/span&gt;         &lt;span style="color: #0000ff"&gt;if&lt;/span&gt; (parameter != &lt;span style="color: #0000ff"&gt;null&lt;/span&gt;)&lt;!--CRLF--&gt;    &lt;span style="color: #606060" id="lnum40"&gt;  40:&lt;/span&gt;         {&lt;!--CRLF--&gt;    &lt;span style="color: #606060" id="lnum41"&gt;  41:&lt;/span&gt;             v = System.Convert.ToInt32(parameter) + v;&lt;!--CRLF--&gt;    &lt;span style="color: #606060" id="lnum42"&gt;  42:&lt;/span&gt;         }&lt;!--CRLF--&gt;    &lt;span style="color: #606060" id="lnum43"&gt;  43:&lt;/span&gt;         &lt;span style="color: #0000ff"&gt;return&lt;/span&gt; &lt;span style="color: #0000ff"&gt;string&lt;/span&gt;.Format(&lt;span style="color: #006080"&gt;"\"{0}\""&lt;/span&gt;, v);&lt;!--CRLF--&gt;    &lt;span style="color: #606060" id="lnum44"&gt;  44:&lt;/span&gt;     }&lt;!--CRLF--&gt;    &lt;span style="color: #606060" id="lnum45"&gt;  45:&lt;/span&gt; }&lt;!--CRLF--&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;使用BindingEngine的用法：&lt;/p&gt;&lt;div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 100%; padding-right: 4px; font-family: 'Courier New', courier, monospace; direction: ltr; font-size: 8pt; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"&gt;  &lt;div style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; height: 174px; color: black; border-right-style: none; font-size: 8pt; padding-top: 0px" id="codeSnippet"&gt;    &lt;span style="color: #606060" id="lnum1"&gt;   1:&lt;/span&gt; View view1 = &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; View();&lt;!--CRLF--&gt;    &lt;span style="color: #606060" id="lnum2"&gt;   2:&lt;/span&gt; View view2 = &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; View();&lt;!--CRLF--&gt;    &lt;span style="color: #606060" id="lnum3"&gt;   3:&lt;/span&gt; ViewModel model = &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; ViewModel();&lt;!--CRLF--&gt;    &lt;span style="color: #606060" id="lnum4"&gt;   4:&lt;/span&gt;&amp;nbsp; &lt;!--CRLF--&gt;    &lt;span style="color: #606060" id="lnum5"&gt;   5:&lt;/span&gt; TextConverter converter = &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; TextConverter();&lt;!--CRLF--&gt;    &lt;span style="color: #606060" id="lnum6"&gt;   6:&lt;/span&gt; BindingEngine.SetPropertyBinding(view1, model, &lt;span style="color: #006080"&gt;"Text"&lt;/span&gt;, &lt;span style="color: #006080"&gt;"Value"&lt;/span&gt;, converter, &lt;span style="color: #0000ff"&gt;null&lt;/span&gt;);&lt;!--CRLF--&gt;    &lt;span style="color: #606060" id="lnum7"&gt;   7:&lt;/span&gt; BindingEngine.SetPropertyBinding(view1, model, &lt;span style="color: #006080"&gt;"Value"&lt;/span&gt;, &lt;span style="color: #006080"&gt;"Value"&lt;/span&gt;);&lt;!--CRLF--&gt;    &lt;span style="color: #606060" id="lnum8"&gt;   8:&lt;/span&gt; BindingEngine.SetPropertyBinding(view2, model, &lt;span style="color: #006080"&gt;"Text"&lt;/span&gt;, &lt;span style="color: #006080"&gt;"Value"&lt;/span&gt;, converter, 2);&lt;!--CRLF--&gt;    &lt;span style="color: #606060" id="lnum9"&gt;   9:&lt;/span&gt; BindingEngine.SetPropertyBinding(view2, model, &lt;span style="color: #006080"&gt;"Value"&lt;/span&gt;, &lt;span style="color: #006080"&gt;"Value"&lt;/span&gt;);&lt;!--CRLF--&gt;    &lt;span style="color: #606060" id="lnum10"&gt;  10:&lt;/span&gt;&amp;nbsp; &lt;!--CRLF--&gt;    &lt;span style="color: #606060" id="lnum11"&gt;  11:&lt;/span&gt; BindingEngine.ClearPropertyBinding(view1, model, &lt;span style="color: #006080"&gt;"Text"&lt;/span&gt;, &lt;span style="color: #006080"&gt;"Value"&lt;/span&gt;);&lt;!--CRLF--&gt;&lt;/div&gt;&lt;/div&gt;&lt;h1 style="padding-bottom: 5px; background-color: gray; margin-top: 24px; padding-left: 5px; padding-right: 5px; margin-bottom: 12px; color: white; font-size: 26px; font-weight: normal; padding-top: 5px"&gt;后续&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;本文只是简略了介绍了一下BindingEngine的实现，对于List控件绑定List并没有进行支持。并且由于使用了Delegate的DynamicInvoke，性能上还有提高余地，可以使用Emit、DynamicMethod来完成取值赋值操作。&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;BindingEngine的源代码和测试代码请点击此&lt;a href="http://files.cnblogs.com/Zhouyongh/BindingSample.rar"&gt;BindingEngineSample&lt;/a&gt;下载，如有问题和建议也欢迎给我留言，谢谢。&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;div&gt;&lt;span style="line-height: 25px; color: #333333; "&gt;&lt;span style="line-height: 25px; background-color: #ffffff; font-family: georgia; color: #333333; "&gt;&lt;span style="padding-bottom: 0px; line-height: 21px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-left: 0px; padding-right: 0px; font-family: 宋体; color: black; font-size: 9pt; padding-top: 0px; "&gt;作者：&lt;/span&gt;&lt;span style="padding-bottom: 0px; line-height: 21px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-left: 0px; padding-right: 0px; font-family: verdana, sans-serif; color: black; font-size: 9pt; padding-top: 0px; "&gt;&lt;a href="http://www.cnblogs.com/Zhouyongh" target="_blank" style="outline-style: none; outline-width: initial; outline-color: initial; text-decoration: none; color: #3d81ee; border-bottom-width: 1px; border-bottom-style: dashed; border-bottom-color: initial; padding-bottom: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px; "&gt;&lt;span style="padding-bottom: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-left: 0px; padding-right: 0px; font-family: 宋体; color: #ff6600; text-decoration: none; padding-top: 0px; "&gt;周永恒&lt;/span&gt;&lt;/a&gt;&amp;nbsp;&lt;br style="padding-bottom: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px; " /&gt;&lt;/span&gt;&lt;span style="padding-bottom: 0px; line-height: 21px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-left: 0px; padding-right: 0px; font-family: 宋体; color: black; font-size: 9pt; padding-top: 0px; "&gt;出处：&lt;/span&gt;&lt;span style="padding-bottom: 0px; line-height: 21px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-left: 0px; padding-right: 0px; font-family: verdana, sans-serif; color: black; font-size: 9pt; padding-top: 0px; "&gt;&lt;a href="http://www.cnblogs.com/Zhouyongh" target="_blank" style="outline-style: none; outline-width: initial; outline-color: initial; text-decoration: none; color: #3d81ee; border-bottom-width: 1px; border-bottom-style: dashed; border-bottom-color: initial; padding-bottom: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px; "&gt;&lt;span style="padding-bottom: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-left: 0px; padding-right: 0px; color: #ff6600; text-decoration: none; padding-top: 0px; "&gt;http://www.cnblogs.com/Zhouyongh&lt;/span&gt;&lt;/a&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;br style="padding-bottom: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px; " /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;p&gt;&lt;span class="Apple-style-span" style="color: #333333; font-family: 宋体; font-size: 12px; line-height: 25px; "&gt;本文版权归作者和博客园共有，欢迎转载，但未经作者同意必须保留此段声明，且在文章页面明显位置给出原文连接，否则保留追究法律责任的权利。&lt;/span&gt;&amp;nbsp;&lt;/p&gt;&lt;img src="http://www.cnblogs.com/Zhouyongh/aggbug/1977768.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/Zhouyongh/archive/2011/03/09/1977768.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/Zhouyongh/archive/2011/01/12/1933414.html</id><title type="text">深入WPF -- Dispatcher（补）</title><summary type="text">惰性是很可怕的东西，时隔一年多，继续写这个WPF系列，本篇文章继续深入研究WPF的线程和Dispatcher，希望朋友们多多支持。</summary><published>2011-01-11T18:59:00Z</published><updated>2011-01-11T18:59:00Z</updated><author><name>周永恒</name><uri>http://www.cnblogs.com/Zhouyongh/</uri></author><link rel="alternate" href="http://www.cnblogs.com/Zhouyongh/archive/2011/01/12/1933414.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/Zhouyongh/archive/2011/01/12/1933414.html"/><content type="html">&lt;p&gt;书接前文，&lt;a href="http://www.cnblogs.com/Zhouyongh/archive/2009/08/31/1557126.html"&gt;前篇文章&lt;/a&gt;介绍了WPF中的Dispatcher，由于概念太多，可能不是那么好理解。这篇文章继续讨论，希望在线程和Dispatcher这个点上，能把它讲透。&lt;/p&gt;  &lt;h1 style="padding-bottom: 5px; background-color: gray; margin-top: 24px; padding-left: 5px; padding-right: 5px; margin-bottom: 12px; color: white; font-size: 26px; font-weight: normal; padding-top: 5px"&gt;从哪说起？&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;按照惯例，在深入问题之前，先找一个插入点，希望这个插入点能为朋友们所理解。&lt;/p&gt;  &lt;p&gt;新建一个Window程序，代码如下：&lt;/p&gt;  &lt;table border="1" cellspacing="0" cellpadding="8" width="400"&gt;&lt;tbody&gt;     &lt;tr&gt;       &lt;td valign="top" width="400"&gt;         &lt;span class="kwrd"&gt;int&lt;/span&gt; WINAPI _tWinMain(HINSTANCE hInstance,　 HINSTANCE hPrevInstance,&lt;br/&gt;                     LPTSTR    lpCmdLine,　 &lt;span class="kwrd"&gt;int&lt;/span&gt;       nCmdShow)&lt;br/&gt;{&lt;br/&gt;    &lt;font color="#0000ff"&gt;RegisterWindowClass&lt;/font&gt;(hInstance);                                      &lt;span class="rem"&gt;//1　&lt;/span&gt;&lt;br/&gt;&lt;br/&gt;    HWND hWnd = &lt;font color="#800080"&gt;CreateWindow&lt;/font&gt;(&lt;font color="#ff0000"&gt;szWindowClass&lt;/font&gt;, szTitle, WS_OVERLAPPEDWINDOW,        &lt;span class="rem"&gt;//2&lt;/span&gt;&lt;br/&gt;        CW_USEDEFAULT, 0, CW_USEDEFAULT,z 0, NULL, NULL, hInstance, NULL);&lt;br/&gt;    &lt;font color="#800080"&gt;ShowWindow&lt;/font&gt;(hWnd, nCmdShow);&lt;br/&gt;&lt;br/&gt;    MSG msg;                                                                     &lt;span class="rem"&gt;//3&lt;/span&gt;&lt;br/&gt;    &lt;span class="kwrd"&gt;while&lt;/span&gt; (GetMessage(&amp;amp;msg, NULL, 0, 0))&lt;br/&gt;    {&lt;br/&gt;        TranslateMessage(&amp;amp;msg);&lt;br/&gt;        DispatchMessage(&amp;amp;msg);&lt;br/&gt;    }&lt;br/&gt;&lt;br/&gt;    &lt;span class="kwrd"&gt;return&lt;/span&gt; (&lt;span class="kwrd"&gt;int&lt;/span&gt;) msg.wParam;&lt;br/&gt;}        &lt;style type="text/css"&gt;.csharpcode, .csharpcode pre{font-size: small;color: black;font-family: consolas, "Courier New", courier, monospace;background-color: #ffffff;/*white-space: pre;*/}.csharpcode pre { margin: 0em; }.csharpcode .rem { color: #008000; }.csharpcode .kwrd { color: #0000ff; }.csharpcode .str { color: #006080; }.csharpcode .op { color: #0000c0; }.csharpcode .preproc { color: #cc6633; }.csharpcode .asp { background-color: #ffff00; }.csharpcode .html { color: #800000; }.csharpcode .attr { color: #ff0000; }.csharpcode .alt {background-color: #f4f4f4;width: 100%;margin: 0em;}.csharpcode .lnum { color: #606060; }&lt;/style&gt;&lt;/td&gt;    &lt;/tr&gt;  &lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;其中的RegisterWindowClass&lt;/p&gt;&lt;table border="1" cellspacing="0" cellpadding="8" width="400"&gt;&lt;tbody&gt;    &lt;tr&gt;      &lt;td valign="top" width="400"&gt;        WORD RegisterWindowClass(HINSTANCE hInstance)&lt;br/&gt;{&lt;br/&gt;    WNDCLASSEX wcex;            wcex.lpszClassName  = &lt;font color="#ff0000"&gt;szWindowClass&lt;/font&gt;;            wcex.lpfnWndProc    = &lt;font color="#800080"&gt;WndProc&lt;/font&gt;;&lt;br/&gt;    ...&lt;br/&gt;}&lt;br/&gt;LRESULT CALLBACK &lt;font color="#800080"&gt;WndProc&lt;/font&gt;(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)&lt;br/&gt;{&lt;br/&gt;    &lt;span class="kwrd"&gt;switch&lt;/span&gt; (message)&lt;br/&gt;    {&lt;br/&gt;    &lt;span class="kwrd"&gt;case&lt;/span&gt; WM_PAINT:&lt;br/&gt;    ...&lt;br/&gt;}        &lt;style type="text/css"&gt;.csharpcode, .csharpcode pre{font-size: small;color: black;font-family: consolas, "Courier New", courier, monospace;background-color: #ffffff;/*white-space: pre;*/}.csharpcode pre { margin: 0em; }.csharpcode .rem { color: #008000; }.csharpcode .kwrd { color: #0000ff; }.csharpcode .str { color: #006080; }.csharpcode .op { color: #0000c0; }.csharpcode .preproc { color: #cc6633; }.csharpcode .asp { background-color: #ffff00; }.csharpcode .html { color: #800000; }.csharpcode .attr { color: #ff0000; }.csharpcode .alt {background-color: #f4f4f4;width: 100%;margin: 0em;}.csharpcode .lnum { color: #606060; }&lt;/style&gt;&lt;/td&gt;    &lt;/tr&gt;  &lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;这个创建窗口并显示的过程如下：&lt;/p&gt;&lt;ol&gt;  &lt;li&gt;调用RegisterWindowClass注册窗口类，关联其中的窗口过程WndProc。 &lt;/li&gt;  &lt;li&gt;调用CreateWindow创建窗口并显示。 &lt;/li&gt;  &lt;li&gt;（主线程）进入GetMessage循环，取得消息后调用DispatchMessage分发消息。 &lt;/li&gt;&lt;/ol&gt;&lt;p&gt;这里的GetMessage循环就是所谓的消息泵，它像水泵一样源源不断的从线程的消息队列中取得消息，然后调用DispatchMessage把消息分发到各个窗口，交给窗口的WndProc去处理。&lt;/p&gt;&lt;p&gt;用一副图来表示这个过程：&lt;/p&gt;&lt;p&gt;&lt;a href="http://images.cnblogs.com/cnblogs_com/Zhouyongh/201101/201101120258086866.png"&gt;&lt;img style="background-image: none; border-right-width: 0px; margin: ; padding-left: 0px; padding-right: 0px; display: inline; float: left; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="_thumb7" border="0" alt="_thumb7" align="left" src="http://images.cnblogs.com/cnblogs_com/Zhouyongh/201101/201101120258178449.png" width="685" height="640" /&gt;&lt;/a&gt; &lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;ol&gt;  &lt;li&gt;鼠标点击。 &lt;/li&gt;  &lt;li&gt;操作系统底层获知这次点击动作，根据点击位置遍历找到对应的Hwnd，构建一个Window消息MSG，把这个消息加入到创建该Hwnd线程的消息队列中去。 &lt;/li&gt;  &lt;li&gt;应用程序主线程处于GetMessage循环中，每次调用GetMessage获取一个消息，如果线程的消息队列为空，则线程会被挂起，直到线程消息队列存在消息线程会被重新激活。 &lt;/li&gt;  &lt;li&gt;调用DispatchMessage分发消息MSG，MSG持有一个Hwnd的字段，指明了消息应该发往的Hwnd，操作系统在第2步构建MSG时会设置这个值。 &lt;/li&gt;  &lt;li&gt;消息被发往Hwnd，操作系统回调该Hwnd对应的窗口过程WndProc，由WndProc来处理这个消息。 &lt;/li&gt;&lt;/ol&gt;&lt;p&gt;这是一个简略的Window消息处理流程，往具体说这个故事会很长，让我们把目光收回到WPF，看看WPF和即将介绍的Dispatcher在这个基础上都做了些什么，又有哪些出彩的地方。&lt;/p&gt;&lt;h1 style="padding-bottom: 5px; background-color: gray; margin-top: 24px; padding-left: 5px; padding-right: 5px; margin-bottom: 12px; color: white; font-size: 26px; font-weight: normal; padding-top: 5px"&gt;仍然从Main函数说起&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;作为应用程序的入口点，我们仍然从Main函数走进WPF。 &lt;/p&gt;&lt;p&gt;新建一个WPF工程，如下：&lt;/p&gt;&lt;p&gt;&lt;a href="http://images.cnblogs.com/cnblogs_com/Zhouyongh/201101/201101120258243263.png"&gt;&lt;img style="background-image: none; border-right-width: 0px; margin: ; padding-left: 0px; padding-right: 0px; display: inline; float: left; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="_thumb21" border="0" alt="_thumb21" align="left" src="http://images.cnblogs.com/cnblogs_com/Zhouyongh/201101/201101120258323866.png" width="211" height="150" /&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;默认的WPF工程中中是找不到传统的Program.cs文件的，它的App.xaml文件的编译动作为ApplicationDefinition，编译后，编译器会自动生成App.g.cs文件，包含了Main函数。如下：&lt;/p&gt;&lt;table border="1" cellspacing="0" cellpadding="8" width="400"&gt;&lt;tbody&gt;    &lt;tr&gt;      &lt;td valign="top" width="400"&gt;                [System.STAThreadAttribute()]&lt;br/&gt;        [System.Diagnostics.DebuggerNonUserCodeAttribute()]&lt;br/&gt;        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; Main()         {&lt;br/&gt;            WpfApplication3.App app = &lt;span class="kwrd"&gt;new&lt;/span&gt; WpfApplication3.App();&lt;br/&gt;            app.InitializeComponent();&lt;br/&gt;            app.Run();&lt;br/&gt;        }        &lt;style type="text/css"&gt;.csharpcode, .csharpcode pre{font-size: small;color: black;font-family: consolas, "Courier New", courier, monospace;background-color: #ffffff;/*white-space: pre;*/}.csharpcode pre { margin: 0em; }.csharpcode .rem { color: #008000; }.csharpcode .kwrd { color: #0000ff; }.csharpcode .str { color: #006080; }.csharpcode .op { color: #0000c0; }.csharpcode .preproc { color: #cc6633; }.csharpcode .asp { background-color: #ffff00; }.csharpcode .html { color: #800000; }.csharpcode .attr { color: #ff0000; }.csharpcode .alt {background-color: #f4f4f4;width: 100%;margin: 0em;}.csharpcode .lnum { color: #606060; }&lt;/style&gt;&lt;/td&gt;    &lt;/tr&gt;  &lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;这里出现了Application类，按MSDN上的解释，&amp;#8220;Application 是一个类，其中封装了 WPF 应用程序特有的功能，包括：应用程序生存期；应用程序范围的窗口、属性和资源管理；命令行参数和退出代码处理；导航&amp;#8221;等。&lt;/p&gt;&lt;p&gt;调用app.Run()之后，按照前面Win32的步骤，应用程序应进入到一个GetMessage的消息泵之中，那么对WPF程序来说，这个消息泵是什么样的呢？又和Dispatcher有什么关系呢？&lt;/p&gt;&lt;h1 style="padding-bottom: 5px; background-color: gray; margin-top: 24px; padding-left: 5px; padding-right: 5px; margin-bottom: 12px; color: white; font-size: 26px; font-weight: normal; padding-top: 5px"&gt;走进Dispatcher&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;Dispatcher的构造函数是私有的，调用Dispacher.CurrentDispatcher会获得当前线程的Dispatcher，Dispatcher内部持有一个静态的所有Dispatcher的List。因为构造函数私有，只能调用CurrentDispatcher来获得Dispatcher，可以保证对同一个线程，只能创建一个Dispatcher。&lt;/p&gt;&lt;p&gt;Dispatcher提供了一个Run函数，来启动消息泵，内部的核心代码是我们所熟悉的，如：&lt;/p&gt;&lt;table border="1" cellspacing="0" cellpadding="8" width="400"&gt;&lt;tbody&gt;    &lt;tr&gt;      &lt;td valign="top" width="400"&gt;                &lt;span class="kwrd"&gt;while&lt;/span&gt; (frame.Continue)&lt;br/&gt;        {&lt;br/&gt;            &lt;span class="kwrd"&gt;if&lt;/span&gt; (!GetMessage(&lt;span class="kwrd"&gt;ref&lt;/span&gt; msg, IntPtr.Zero, 0, 0))&lt;br/&gt;                &lt;span class="kwrd"&gt;break&lt;/span&gt;;&lt;br/&gt;            TranslateAndDispatchMessage(&lt;span class="kwrd"&gt;ref&lt;/span&gt; msg);&lt;br/&gt;        }        &lt;style type="text/css"&gt;.csharpcode, .csharpcode pre{font-size: small;color: black;font-family: consolas, "Courier New", courier, monospace;background-color: #ffffff;/*white-space: pre;*/}.csharpcode pre { margin: 0em; }.csharpcode .rem { color: #008000; }.csharpcode .kwrd { color: #0000ff; }.csharpcode .str { color: #006080; }.csharpcode .op { color: #0000c0; }.csharpcode .preproc { color: #cc6633; }.csharpcode .asp { background-color: #ffff00; }.csharpcode .html { color: #800000; }.csharpcode .attr { color: #ff0000; }.csharpcode .alt {background-color: #f4f4f4;width: 100%;margin: 0em;}.csharpcode .lnum { color: #606060; }&lt;/style&gt;&lt;style type="text/css"&gt;.csharpcode, .csharpcode pre{font-size: small;color: black;font-family: consolas, "Courier New", courier, monospace;background-color: #ffffff;/*white-space: pre;*/}.csharpcode pre { margin: 0em; }.csharpcode .rem { color: #008000; }.csharpcode .kwrd { color: #0000ff; }.csharpcode .str { color: #006080; }.csharpcode .op { color: #0000c0; }.csharpcode .preproc { color: #cc6633; }.csharpcode .asp { background-color: #ffff00; }.csharpcode .html { color: #800000; }.csharpcode .attr { color: #ff0000; }.csharpcode .alt {background-color: #f4f4f4;width: 100%;margin: 0em;}.csharpcode .lnum { color: #606060; }&lt;/style&gt;&lt;/td&gt;    &lt;/tr&gt;  &lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;这里出现了一个Frame的概念，暂且不谈，来看看Dispatcher相对于传统的消息循环，有哪些改进的地方。&lt;/p&gt;&lt;h1 style="padding-bottom: 5px; background-color: gray; margin-top: 24px; padding-left: 5px; padding-right: 5px; margin-bottom: 12px; color: white; font-size: 26px; font-weight: normal; padding-top: 5px"&gt;Dispatcher的新意&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;在Winform的消息循环中，&lt;/p&gt;&lt;ol&gt;  &lt;li&gt;为了线程安全，调用Control的Invoke或者BeginInvoke方法可以在创建控件的线程上执行委托，方法的返回值分别为object和IAsyncResult。尽管可以使用IAsyncResult的IsCompleted和AsyncWaitHandle等方法来轮询或者等待委托的执行，但对于对任务的控制来讲，这个粒度是不够的，我们不能取消（Cancel）一个已经调用BeginInvoke的委托任务，也不能更换两个BeginInvoke的执行顺序。 &lt;/li&gt;  &lt;li&gt;更为友好的接口支持，Windows编程中，在窗口消息循环中加入Hook是常见的需求，Dispatcher提供了DispatcherHooks类，以Event的形式对外提供了OperationAborted，OperationCompleted，OperationPosted等事件。 &lt;/li&gt;&lt;/ol&gt;&lt;p&gt;这里的Operation指的是DispatcherOperation，为了更好的控制消息循环，WPF引入了DispatcherOperation来封装Window消息，这个DispatcherOperation如下：&lt;/p&gt;&lt;h1 style="padding-bottom: 5px; background-color: gray; margin-top: 24px; padding-left: 5px; padding-right: 5px; margin-bottom: 12px; color: white; font-size: 26px; font-weight: normal; padding-top: 5px"&gt;DispatcherOpration&lt;/strong&gt;&lt;/p&gt;&lt;table border="1" cellspacing="0" cellpadding="8" width="400"&gt;&lt;tbody&gt;    &lt;tr&gt;      &lt;td valign="top" width="400"&gt;        &lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 12px"&gt;&lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;sealed&lt;/span&gt; &lt;span style="color: #0000ff"&gt;class&lt;/span&gt; DispatcherOperation &lt;br/&gt;{ &lt;br/&gt;    &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; Dispatcher Dispatcher { &lt;span style="color: #0000ff"&gt;get&lt;/span&gt;; } &lt;br/&gt;    &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; DispatcherPriority Priority { &lt;span style="color: #0000ff"&gt;get&lt;/span&gt;; &lt;span style="color: #0000ff"&gt;set&lt;/span&gt;; } &lt;br/&gt;    &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;object&lt;/span&gt; Result { &lt;span style="color: #0000ff"&gt;get&lt;/span&gt;; } &lt;br/&gt;    &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; DispatcherOperationStatus Status { &lt;span style="color: #0000ff"&gt;get&lt;/span&gt;; }&lt;br/&gt;    &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;event&lt;/span&gt; EventHandler Aborted; &lt;br/&gt;    &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;event&lt;/span&gt; EventHandler Completed;&lt;br/&gt;    &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;bool&lt;/span&gt; Abort(); &lt;br/&gt;    &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; DispatcherOperationStatus Wait(); &lt;br/&gt;    &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; DispatcherOperationStatus Wait(TimeSpan timeout); &lt;br/&gt;}&lt;br/&gt;&lt;/pre&gt;      &lt;/td&gt;    &lt;/tr&gt;  &lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;DispatcherOperation类看起来还是比较简单明了的，以属性的形式暴露了Result（结果），Status（状态），以及用事件来指出这个Operation何时结束或者取消。其中比较有意思的是Priority属性，从字面来看，它表示了DispatcherOperation的优先级，而且提供了get和set方法，也就是说，这个DispatcherOperation是可以在运行时更改优先级的。那么这个优先级是怎么回事，Dispatcher又是如何处理DispatcherOperation的呢，让我们深入DispatcherOperation，来看看它是如何被处理的。&lt;/p&gt;&lt;h1 style="padding-bottom: 5px; background-color: gray; margin-top: 24px; padding-left: 5px; padding-right: 5px; margin-bottom: 12px; color: white; font-size: 26px; font-weight: normal; padding-top: 5px"&gt;深入DispatcherOperation（DO）&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;所谓深入，也要有的放矢，从三个方面来谈一下DispatcherOperation：&lt;/p&gt;&lt;ol&gt;  &lt;li&gt;DispatcherOperation是如何被创建的。 &lt;/li&gt;  &lt;li&gt;DispatcherOperation是何时被执行的。 &lt;/li&gt;  &lt;li&gt;DispatcherOperation是怎样被执行的。 &lt;/li&gt;&lt;/ol&gt;&lt;p&gt;Dispatcher提供了BeginInvoke和Invoke两个方法，其中BeginInvoke的返回值是DispatcherOperation，Invoke函数的内部调用了BeginInvoke，也就是说，DispatcherOperation就是在这两个函数中被创建出来的。我们可以调用这两个函数创建新的DO，WPF内部也调用了这两个函数，把Window消息转化为DispatcherOperation，用一副图表示如下：&lt;/p&gt;&lt;p&gt;&lt;a href="http://images.cnblogs.com/cnblogs_com/Zhouyongh/201101/201101120259509166.png"&gt;&lt;img style="background-image: none; border-bottom: 0px; border-left: 0px; margin: ; padding-left: 0px; padding-right: 0px; display: inline; float: left; border-top: 0px; border-right: 0px; padding-top: 0px" title="_thumb2" border="0" alt="_thumb2" align="left" src="http://images.cnblogs.com/cnblogs_com/Zhouyongh/201101/201101120259561537.png" width="609" height="270" /&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;ol&gt;  &lt;li&gt;窗口过程WndProc接收到Window消息，调用Dispatcher的Invoke方法，创建一个DispatcherOperation。Dispatcher内部持有一个DispatcherOperation的队列，用来存放所有创建出来的DispatcherOperation。默认一个DO被创建出来后，会加入到这个队列中去。WndProc调用Invoke的时候比较特殊，他传递的优先级DispatcherPriority为Send，这是一个特殊的优先级，在Invoke时传递Send优先级WPF会直接执行这个DO，而不把它加入到队列中去。 &lt;/li&gt;  &lt;li&gt;用户也可以随时调用Invoke或者BeginInvoke方法加入新的DO，在DispatcherOperation处理的时候也可能会调用BeginInvoke加入新的DO。 &lt;/li&gt;&lt;/ol&gt;&lt;p&gt;DO被加入到Dispatcher的队列中去，那么这个队列又是何时被处理呢？Dispatcher在创建的时候，创建了一个隐藏的Window，在DO加入到队列后，Dispatcher会向自己的隐藏Window发送一个自定义的Window消息（DispatcherProcessQueue）。当收到这个消息后，会按照优先级和队列顺序取出第一个DO并执行：&lt;/p&gt;&lt;ol&gt;  &lt;li&gt;用户调用BeginInvoke。 &lt;/li&gt;  &lt;li&gt;Dispatcher创建了一个DO，加入到DO队列中去，并向自己的隐藏窗口Post自定义消息（DispatcherProcessQueue）。 &lt;/li&gt;  &lt;li&gt;创建隐藏窗口时会Hook它的消息，当收到的消息为DispatcherProcessQueue时，按照优先级取出队列中的一个DO，并执行。 &lt;/li&gt;&lt;/ol&gt;&lt;p&gt;每加入一个DO就会申请处理DO队列，在DO的优先级（DispatcherPriority）被改变的时候也会处理DO队列，DO在创建时声明了自己的优先级，这个优先级会影响到队列的处理顺序。&lt;/p&gt;&lt;h1 style="padding-bottom: 5px; background-color: gray; margin-top: 24px; padding-left: 5px; padding-right: 5px; margin-bottom: 12px; color: white; font-size: 26px; font-weight: normal; padding-top: 5px"&gt;DispatcherTimer&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;鉴于线程亲缘性，当需要创建Timer并访问UI对象时，多使用DispatcherTimer。DispatcherTimer的一个简单用法如下：&lt;/p&gt;&lt;table border="1" cellspacing="0" cellpadding="8" width="403"&gt;&lt;tbody&gt;    &lt;tr&gt;      &lt;td valign="top" width="401"&gt;        &lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; height: 22px; font-size: 12px"&gt;  var dispatcherTimer = &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; System.Windows.Threading.DispatcherTimer();     dispatcherTimer.Tick += &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; EventHandler(dispatcherTimer_Tick);&lt;br/&gt;  dispatcherTimer.Interval = &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; TimeSpan(0,0,1);&lt;br/&gt;&lt;p&gt;  dispatcherTimer.Start(); &lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; height: 6px; font-size: 12px"&gt;&lt;/pre&gt;&lt;/pre&gt;&lt;/pre&gt;      &lt;/td&gt;    &lt;/tr&gt;  &lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;在DispatcherTimer的内部，Timer的Tick事件处理也被包装成了DispatcherOperation，并调用BeginInvoke加入到Dispatcher中去。当这个DO被执行后，如果DispatcherTimer的状态仍然为Enable，DispatcherTimer会继续调用BeginInvoke加入新的DO。关于Timer的时间处理，Dispatcher会向自己的隐藏窗口调用SetTimer并计算时间间隔，当然，因为DispatcherOperation有优先级，不能保状正好在时间间隔时执行这个DO，这个执行的时间会比预计时间偏后而不会超前。&lt;/p&gt;&lt;h1 style="padding-bottom: 5px; background-color: gray; margin-top: 24px; padding-left: 5px; padding-right: 5px; margin-bottom: 12px; color: white; font-size: 26px; font-weight: normal; padding-top: 5px"&gt;UI线程和Dispatcher&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;通常，WPF启动时具有两个线程，一个处理呈现（Render），另一个用于管理UI。关于Render线程，请参见&lt;a href="http://www.cnblogs.com/Zhouyongh/archive/2009/11/30/1613628.html"&gt;前文&lt;/a&gt;。这个管理UI的线程通常被称为UI线程。在WPF中，所有UI对象的基类为DispatcherObject，WPF在对所有DispatcherObject属性操作前进行了线程亲缘性校验，只有在创建UI对象的线程中才可以访问该UI对象。&lt;/p&gt;&lt;p&gt;前面提到，由于Dispatcher构造函数私有，一个线程最多只能有一个Dispatcher。对UI线程来说，Dispatcher的主要作用就是对任务项（DispatcherOperation）进行排队。对UI对象来说，DispatcherObject有一个Dispatcher属性，可以获得创建该UI对象线程的Dispatcher。这种设计通过Dispatcher统一了UI对象的操作，从使用上隔离了UI对象和线程间的关系。&lt;/p&gt;&lt;h1 style="padding-bottom: 5px; background-color: gray; margin-top: 24px; padding-left: 5px; padding-right: 5px; margin-bottom: 12px; color: white; font-size: 26px; font-weight: normal; padding-top: 5px"&gt;多线程&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;多线程操作简单分为两种：多工作线程和多UI线程，当然，也可以有多工作多UI线程，思路是一样的，省去不谈。&lt;/p&gt;&lt;p&gt;程序启动时默认的主线程就是UI线程，它在调用Application.Run（也就是Dispatcher.Run）之后进入了一个GetMessage的循环中，对Window消息进行响应并构建执行一个个的DispatcherOperation。默认对UI对象的操作都是在这个主线程中，如果进行耗时很长的操作就会造成UI线程长时间不能继续响应Window消息，造成界面假死等一些的UI响应问题。对这种耗时较长的操作一般需要工作线程来帮忙，操作结束后再通过Dispatcher把结果Invoke到UI线程，如：&lt;/p&gt;&lt;table border="1" cellspacing="0" cellpadding="8" width="400"&gt;&lt;tbody&gt;    &lt;tr&gt;      &lt;td valign="top" width="400"&gt;        &lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; height: 23px; font-size: 12px"&gt;TextBlock textBlock = &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; TextBlock() { Text = "&lt;span style="color: #8b0000"&gt;1&lt;/span&gt;" }; &lt;br/&gt;Thread thread = &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; Thread(&lt;span style="color: #0000ff"&gt;new&lt;/span&gt; ThreadStart(() =&amp;gt; &lt;br/&gt;    { &lt;br/&gt;        &lt;span style="color: #008000"&gt;//做一些耗时操作，这里用线程休眠10秒来模拟 &lt;/span&gt;&lt;br/&gt;         Thread.Sleep(TimeSpan.FromSeconds(10));&lt;br/&gt;        textBlock.Dispatcher.Invoke(&lt;span style="color: #0000ff"&gt;new&lt;/span&gt; Action(() =&amp;gt; &lt;br/&gt;            { &lt;br/&gt;                textBlock.Text = "&lt;span style="color: #8b0000"&gt;2&lt;/span&gt;"; &lt;br/&gt;            })); &lt;br/&gt;    })); thread.Start();&lt;br/&gt;&lt;/pre&gt;      &lt;/td&gt;    &lt;/tr&gt;  &lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;当然，除了新建工作线程，也可以使用BackgroundWorker或者线程池中线程来进行耗时操作，操作结束后需要调用UI对象Dispatcher的Invoke或者BeginInvoke方法来操作UI，否则会抛出InvalidOperationException来提示不可跨线程访问UI对象。&lt;/p&gt;&lt;p&gt;这种多工作线程是很常见的，一般我们讨论的多线程大多指这种多工作线程单一UI线程，那么如何创建多UI线程的程序呢？&lt;/p&gt;&lt;h1 style="padding-bottom: 5px; background-color: gray; margin-top: 24px; padding-left: 5px; padding-right: 5px; margin-bottom: 12px; color: white; font-size: 26px; font-weight: normal; padding-top: 5px"&gt;多UI线程&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;在谈多UI线程之前，先说说多UI线程使用的场景：&lt;/p&gt;&lt;p&gt;大多数情况下，我们是不需要多UI线程的，所谓多UI线程，就是指有两个或者两个以上的线程创建了UI对象。这种做法的好处是两个UI线程会分别进入各自的GetMessage循环，如果是需要多个监视实时数据的UI，或者说使用了DirectShow一些事件密集的程序，可以考虑新创建一个UI线程（GetMessage循环）来减轻单一消息泵的压力。当然，这样做的坏处也很多，不同UI线程中的UI对象互相访问是需要进行Invoke通信的，为了解决这个问题，WPF提供了VisualTarget来用于跨线程将一个对象树连接到另一个对象树，如：&lt;/p&gt;&lt;table border="1" cellspacing="0" cellpadding="1" width="400"&gt;&lt;tbody&gt;    &lt;tr&gt;      &lt;td valign="top" width="400"&gt;        &lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; height: 20px; font-size: 12px"&gt;    &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;class&lt;/span&gt; VisualHost : FrameworkElement&lt;br/&gt;    {&lt;br/&gt;        &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; Visual Child&lt;br/&gt;        {&lt;br/&gt;            &lt;span style="color: #0000ff"&gt;get&lt;/span&gt; { &lt;span style="color: #0000ff"&gt;return&lt;/span&gt; _child; }&lt;br/&gt;            &lt;span style="color: #0000ff"&gt;set&lt;/span&gt;&lt;br/&gt;            {&lt;br/&gt;                &lt;span style="color: #0000ff"&gt;if&lt;/span&gt; (_child != &lt;span style="color: #0000ff"&gt;null&lt;/span&gt;)&lt;br/&gt;                    RemoveVisualChild(_child);&lt;br/&gt;                _child = &lt;span style="color: #0000ff"&gt;value&lt;/span&gt;;&lt;br/&gt;                &lt;span style="color: #0000ff"&gt;if&lt;/span&gt; (_child != &lt;span style="color: #0000ff"&gt;null&lt;/span&gt;)&lt;br/&gt;                    AddVisualChild(_child);&lt;br/&gt;            }&lt;br/&gt;        }&lt;br/&gt;        &lt;span style="color: #0000ff"&gt;protected&lt;/span&gt; &lt;span style="color: #0000ff"&gt;override&lt;/span&gt; Visual GetVisualChild(&lt;span style="color: #0000ff"&gt;int&lt;/span&gt; index)&lt;br/&gt;        {&lt;br/&gt;            &lt;span style="color: #0000ff"&gt;if&lt;/span&gt; (_child != &lt;span style="color: #0000ff"&gt;null&lt;/span&gt; &amp;amp;&amp;amp; index == 0)&lt;br/&gt;                &lt;span style="color: #0000ff"&gt;return&lt;/span&gt; _child;&lt;br/&gt;            &lt;span style="color: #0000ff"&gt;else&lt;/span&gt;&lt;br/&gt;                &lt;span style="color: #0000ff"&gt;throw&lt;/span&gt; &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; ArgumentOutOfRangeException("&lt;span style="color: #8b0000"&gt;index&lt;/span&gt;");&lt;br/&gt;        }&lt;br/&gt;        &lt;span style="color: #0000ff"&gt;protected&lt;/span&gt; &lt;span style="color: #0000ff"&gt;override&lt;/span&gt; &lt;span style="color: #0000ff"&gt;int&lt;/span&gt; VisualChildrenCount&lt;br/&gt;        {&lt;br/&gt;            &lt;span style="color: #0000ff"&gt;get&lt;/span&gt; { &lt;span style="color: #0000ff"&gt;return&lt;/span&gt; _child != &lt;span style="color: #0000ff"&gt;null&lt;/span&gt; ? 1 : 0; }&lt;br/&gt;        }&lt;br/&gt;        &lt;span style="color: #0000ff"&gt;private&lt;/span&gt; Visual _child;&lt;br/&gt;    }&lt;br/&gt;&lt;/pre&gt;      &lt;/td&gt;    &lt;/tr&gt;  &lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;在另一个UI线程下的VisualTarget：&lt;/p&gt;&lt;table border="1" cellspacing="0" cellpadding="1" width="396"&gt;&lt;tbody&gt;    &lt;tr&gt;      &lt;td valign="top" width="394"&gt;        &lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 12px"&gt;    Window win = &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; Window();&lt;br/&gt;    win.Loaded += (s, ex) =&amp;gt;&lt;br/&gt;        {&lt;br/&gt;            &lt;font color="#c0504d"&gt;VisualHost &lt;/font&gt;vh = &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; &lt;font color="#c0504d"&gt;VisualHost&lt;/font&gt;();&lt;br/&gt;            HostVisual hostVisual = &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; HostVisual();&lt;br/&gt;            vh.Child = hostVisual;&lt;br/&gt;            win.Content = vh;&lt;br/&gt;            Thread thread = &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; Thread(&lt;span style="color: #0000ff"&gt;new&lt;/span&gt; ThreadStart(() =&amp;gt;&lt;br/&gt;            {&lt;br/&gt;                VisualTarget visualTarget = &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; VisualTarget(hostVisual);&lt;br/&gt;                DrawingVisual dv = &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; DrawingVisual();&lt;br/&gt;                &lt;span style="color: #0000ff"&gt;using&lt;/span&gt; (var dc = dv.RenderOpen())&lt;br/&gt;                {&lt;br/&gt;                    dc.DrawText(&lt;span style="color: #0000ff"&gt;new&lt;/span&gt; FormattedText("&lt;span style="color: #8b0000"&gt;UI from another UI thread&lt;/span&gt;",&lt;br/&gt;                        System.Globalization.CultureInfo.GetCultureInfo("&lt;span style="color: #8b0000"&gt;en-us&lt;/span&gt;"),&lt;br/&gt;                        FlowDirection.LeftToRight,&lt;br/&gt;                        &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; Typeface("&lt;span style="color: #8b0000"&gt;Verdana&lt;/span&gt;"),&lt;br/&gt;                        32,&lt;br/&gt;                        Brushes.Black), &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; Point(10, 0));&lt;br/&gt;                }&lt;br/&gt;                visualTarget.RootVisual = dv;&lt;br/&gt;                Dispatcher.Run();  //&lt;font color="#008000"&gt;启动Dispatcher&lt;/font&gt;&amp;nbsp;            }));&lt;br/&gt;            thread.SetApartmentState(ApartmentState.STA);&lt;br/&gt;            thread.IsBackground = &lt;span style="color: #0000ff"&gt;true&lt;/span&gt;;&lt;br/&gt;            thread.Start();&lt;br/&gt;        };&lt;br/&gt;&lt;p&gt;    win.Show();&lt;/p&gt;&lt;pre&gt;&amp;nbsp;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;/pre&gt;&lt;/pre&gt;      &lt;/td&gt;    &lt;/tr&gt;  &lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;当然，这个多UI线程只是为了更好的捋清线程间的关系，实际使用中的例子并不是很常见。&lt;/p&gt;&lt;h1 style="padding-bottom: 5px; background-color: gray; margin-top: 24px; padding-left: 5px; padding-right: 5px; margin-bottom: 12px; color: white; font-size: 26px; font-weight: normal; padding-top: 5px"&gt;总结&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;Dispatcher是WPF中很重要的一个概念，WPF所有UI对象都是运行在Dispatcher上的。Dispatcher的一些设计思路包括Invoke和BeginInvoke等从WinForm时代就是一直存在的，只是使用了Dispatcher来封装这些线程级的操作。剩余一些概念包括跨线程通信的Freezable以及详细的优先级顺序DispatcherPriority本文都没有细谈，以后的文章中会逐步介绍，希望大家多多支持，谢谢。&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;span style="line-height: 25px; background-color: #ffffff; font-family: georgia; color: #333333" class="Apple-style-span"&gt;&lt;span style="padding-bottom: 0px; line-height: 21px; margin: 0px; padding-left: 0px; padding-right: 0px; font-family: 宋体; color: black; font-size: 9pt; padding-top: 0px"&gt;作者：&lt;/span&gt;&lt;span style="padding-bottom: 0px; line-height: 21px; margin: 0px; padding-left: 0px; padding-right: 0px; font-family: verdana, sans-serif; color: black; font-size: 9pt; padding-top: 0px"&gt;&lt;a style="border-bottom: 1px dashed; padding-bottom: 0px; margin: 0px; outline-style: none; outline-color: ; padding-left: 0px; padding-right: 0px; color: #3d81ee; text-decoration: none; padding-top: 0px" href="http://www.cnblogs.com/Zhouyongh" target="_blank"&gt;&lt;span style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; font-family: 宋体; color: #ff6600; text-decoration: none; padding-top: 0px"&gt;周永恒&lt;/span&gt;&lt;/a&gt;    &lt;br style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px" /&gt;&lt;/span&gt;&lt;span style="padding-bottom: 0px; line-height: 21px; margin: 0px; padding-left: 0px; padding-right: 0px; font-family: 宋体; color: black; font-size: 9pt; padding-top: 0px"&gt;出处：&lt;/span&gt;&lt;span style="padding-bottom: 0px; line-height: 21px; margin: 0px; padding-left: 0px; padding-right: 0px; font-family: verdana, sans-serif; color: black; font-size: 9pt; padding-top: 0px"&gt;&lt;a style="border-bottom: 1px dashed; padding-bottom: 0px; margin: 0px; outline-style: none; outline-color: ; padding-left: 0px; padding-right: 0px; color: #3d81ee; text-decoration: none; padding-top: 0px" href="http://www.cnblogs.com/Zhouyongh" target="_blank"&gt;&lt;span style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; color: #ff6600; text-decoration: none; padding-top: 0px"&gt;http://www.cnblogs.com/Zhouyongh&lt;/span&gt;&lt;/a&gt;&amp;nbsp;&amp;nbsp; &lt;br style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px" /&gt;&lt;/span&gt;&lt;/span&gt;&lt;p&gt;&lt;span style="font-family: 宋体; font-size: 12px" class="Apple-style-span"&gt;本文版权归作者和博客园共有，欢迎转载，但未经作者同意必须保留此段声明，且在文章页面明显位置给出原文连接，否则保留追究法律责任的权利。&lt;/span&gt;&lt;/p&gt;&lt;img src="http://www.cnblogs.com/Zhouyongh/aggbug/1933414.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/Zhouyongh/archive/2011/01/12/1933414.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry></feed>
