WPF插件式框架

前言

  标题有点大,本文主要介绍了WPF插件式框架的一个思路,代码来自于以前给朋友写的一个Sample,细节地方不去关注,大致谈谈想法。

插件式架构

  插件式(AddIn)架构,不是一个新名词,应用程序采用插件式拼合,可以更好的支持扩展。很多著名的软件都采用了插件式的架构,如常见的IDE:EClipse,VisualStudio等等。

  这些插件式架构在实现上各有特色,但是基本原理大致相同:

  1. 定义插件框架,用来下载,创建,销毁插件,并管理插件间的通信等等。
  2. 定义插件契约,定义统一的接口规范。
  3. 实现插件组件,组件实现插件契约,在运行时可以被插件框架所发现并集成。

  关于插件式架构的实现技术,可以有很多选择,使用动态链接库的导出函数,使用COM技术等等,这里选择的是.net的MEF,MEF(Managed Extensibility Framework)是微软集成在.net framework中的扩展性管理框架,VisualStudio2010就是使用了MEF来管理插件,关于MEF的具体使用,请参见MSDN,这里不详细介绍了。

设计与实现

  工程目录以及架构图如下所示:

WPF插件式框架_第1张图片WPF插件式框架_第2张图片

  Illusion中使用MEF实现了插件管理,通用的Services等等,Illusion作为一个Core模块,可以参见前文

  Workbench定义了插件的工作台,定义了UI的布局。

  Presentation定义了UI的具体实现,可以添加/替换UI的表现,默认提供了Ribbon和Default两种形式,可以点击选项-显示框架来动态切换整个UI。

总结

  插件式架构应用程序不是什么新奇的东西,把UI布局和UI表现分离,并支持插件式架构是设计时的一些想法,具体到项目应用还需要一定的完善。代码放置很久了,拿出来分享一下,希望对朋友们有所帮助。

  项目代码可以点击这里下载。

 

面向对象(OO)程序设计

2012-02-16 11:04 by 周永恒, 1291 visits, 收藏编辑

前言

  本文主要介绍面向对象(OO)程序设计,以维基百科的解释:

面向对象程序设计英语Object-oriented programming,缩写:OOP),指一种程序设计范型,同时也是一种程序开发的方法。它将对象作为程序的基本单元,将程序和数据封装其中,以提高软件的重用性、灵活性和扩展性。

  简略来说,面向对象程序设计,指采用了面向对象的方法来进行程序设计。设计指一种把计划、规划、设想通过视觉传达出来的活动过程,它是一种创造性,积累性,实践性的工作。提笔写设计的文章是很有压力的,它不像深入一个知识点一样让人容易有的放矢,一千个读者心中有一千个哈姆雷特,同样的项目两个人来做架构肯定不一样。包括我,每几年对设计都会有一些不同的看法,回头来看自己的代码也总会挑出很多不足,世界是不完美的,设计却希望尽求完美,闲话不说,来进入本文的正题,看看从何谈起。

面向过程程序设计

  面向过程程序设计不是面向对象程序设计的前提,从面向过程谈起主要是因为自面向对象(OO)程序设计一提出,就有太多的两者对比。在这样的对比中,面向过程被形容成老化,腐朽,僵硬的设计模式,它自上而下,按照功能逐渐细化,实现快速但面对变化时束手无策。相对而言面向对象具有封装性,重用性,扩展性等一系列优点,言而总之:“还面向过程??你out了,来面向对象吧。。。”

  C语言是面向过程的代表,它在1972年由贝尔实验室的D.M.Ritchie提出,在Unix系统中大放异彩,直至今天在系统软件,图形动画,嵌入开发等众多领域中还保持着旺盛的生命力。程序设计这个概念,伴随着程序开发被提出,最简略的被描述为 程序设计=数据结构+算法,通俗一点的说程序设计指的是设计、编制、调试程序的方法和过程。人是善于思考总结的,在漫长的面向过程的程序开发中,一些设计原则被提出,用以更好的指导设计:

  1. 模块原则:使用简单的接口拼合简单的部件。
  2. 清晰原则:清晰胜于技巧。
  3. 组合原则:设计时考虑拼接组合。
  4. 分离原则:策略同机制分离,接口同引擎分离。
  5. 简洁原则:设计要简洁,复杂度能低则低。
  6. 透明性原则:设计要可见,以便审查和调试。
  7. 健壮原则:健壮源于透明和简洁。
  8. 优化原则:雕琢之前先要有原型,跑之前先学会走,不要过早优化。
  9. 扩展原则:设计着眼于未来,未来总比预想快。

  以上原则参考自《Unix编程艺术》,书中总结了17种原则来指导程序设计,精简为一句话就是Unix哲学“KISS—Keep It Simple, Stupid!”,保持简单。

  KISS,Keep Simple,Keep是它的核心词,底层的API设计,可以尽量保持简洁清晰,外部的需求变化,Keep?你Hold得住么?

需求变化,你Hold得住么?

  你Hold不住!

  变化来源于对事物认识的发展和外部业务的变更,当然实际中变化可能来自于更多方面。你不能拒绝变化,你只能拥抱变化,在长期的程序设计中,两条设计原则被提出:

  1. 简洁,用更长的三个词来说应该是简洁,清晰,透明。程序应该易于读懂,易于维护,最好有文档注释。世界在变,规则在变,今天精巧的设计,可能成为明天修改的沉重包袱。
  2. 重构,在不改变软件现有的功能上,通过调整程序代码而改善软件质量,性能等。面向过程中重构的原则性目标在于提高正交性,所谓正交性,是指任何操作均无副作用,每一个动作只改变一件事,不会影响其它。具体到API设计就是一个API中不应做两件事,一个粗粒度内部做几种事情的接口可以细化为多个细粒度的接口,“只做好一件事”,这个忠告不仅是针对简单性的建议,对正交性也是同等程度的强调。

  按照正交性的设想,我们应该打造一个纯正交的系统,在这个设计中,任何操作均无副作用,每一个动作只改变一件事不会影响其它,改变一件事情一个具体方面的方法只有一个。想法是完美的,世界是复杂的,软件要能做到拥抱变化,设计希望达到高内聚(模块内元素紧密结合),低耦合(模块间依赖尽可能低),那么如何来拥抱变化呢?

让它“活”起来

  程序最有魅力的事情在于创造,程序员使用代码来完成程序的创造。一花一世界,一木一浮生,作为粘土世界的上帝,我们采取了很多的努力来完成我们的设计:

  1. 分清程序中可变和不可变的部分,相对来说,数据是不可变的,算法是可变的,我们设计好相对稳定的数据,再细化算法,应对变更。
  2. 以模块化来划分程序,按功能来划分模块,这样从纵向看,程序是由一个个的模块组成的,从横向看,我们定义好模块间通信的接口,程序就是由模块组织起来的联合体。

  程序像流水线一样工作起来了,数据从上到下开始运作,但是变化仍然无处不在,大修小补依然无法避免。如果模块设计的足够独立,程序的正交性足够好,变动还在可控范围之内。一旦变化跨越多个模块,程序经过多次大修,就会有种想把它捏回泥巴的冲动。

  外部的变化还在继续,里面依旧是勤恳,冰冷的泥块,怎么来拥抱变化?对,伸出你的金手指,让它“活”起来。

对象

  英雄应运而生,对象应责而生。我们点“活”了对象,就是为了让它解决事情承担责任。从:

   1: struct Data
   2: {
   3:     int d;
   4: };
   5: void increase_data(Data* data)
   6: {
   7:     printf("过程调用,数据为: %d", ++data->d);
   8: }
   9: increase_data(&Data());

  到

   1: public class DataWorker
   2: {
   3:     private int data;
   4:     public void Increase()
   5:     {
   6:         Console.WriteLine("对象调用,数据为: {0}", ++data);
   7:     }
   8: }
   9: new DataWorker().Increase();

  把传统的数据和处理数据的函数封装起来,用DataWorker对象来表示,数据变成了对象的状态,函数变成了对象的方法(行为)。一个对象被我们点“活”了,它负责处理一件事情,把责任下放是点活对象的出发点--“变化太快了,面面俱到的管理让我疲于奔命,你就负责处理这块事情吧,由你来应对这块事情的变化”。

替换

  对象被我们点活了,它们各尽其责来处理自己的事情,程序处理被变成了一个个对象间的相互协作,如果有变化产生我们找到负责的对象,由它来处理变化。想法是完美的,可是具体到对象,它怎么来应对变化?修改自己的方法(行为)?

  对象是我们点活的,责任是我们分配的,方法(行为)是我们指定的,发生变化了还要我们来修改它的方法(行为),那绕一圈点活它干嘛?和面向过程中直接修改对应的函数有啥区别?是的,可能方便在于比较容易定位到它,但是你修改了一个对象后,如何保证和它协作的别的对象没有意见,不会造反?

  从现实来讲,作为一个老总,指派了一个区域经理来负责一块业务,负责的业务出现了问题,你会对它的业务指手画脚来重新教育他该怎么做么?不会的,不要让自己陷入泥潭,首先信任,不行就炒了他,换一个。

  应对变化的关键点在于替换,这样才不会使自己陷入细节。替,顶替,表示新对象可以承担旧对象的职责,对协作的别的对象没有影响。换,表示要能应对变化,更改处理责任的具体方法(行为)。这是一个共性和变性的描述,那么怎么用程序语言来表示?

  类是面向对象程序语言中的一个概念,表示具有相同行为对象的模板,类声明了对象的行为,它描述了该类对象能够做什么以及如何做的方法。一个类的不同对象具有相同的成员(属性、方法等),用类来表示对象的共性,那么怎么来表示变性呢?

  类之间支持继承,可以用父类和子类来表示这层关系,用自然语言来形容,父类是子类一种更高程度的抽象,比如动物和哺乳动物。子类可以添加新的行为或者重新定义父类的行为来完成变化。允许子类来重定义父类的行为,在对象间的相互协作中尤为重要,可以把不同的子类对象都当做父类对象来看,这样可以屏蔽不同子类对象间的差异。在需求变化时,通过子类对象的替换来在不改变对象协作关系的情况下完成变化,这种特性也被称为多态。

  封装,继承,多态,被称为面向对象技术中的三大机制,那么回到本文的主题,什么叫面向对象呢?

面向对象

  所谓面向对象,面向两个字很重要--“我的眼里只有你”,面向对象的哲学在于把软件(世界)看成是由各种各样具有特定职责的对象所组成,不同对象之间的相互作用和通讯构成了整个软件(世界)。以面向对象的角度去进行程序设计,需要至少以下三步:

  1. 发现(设计)对象;
  2. 确定对象的职责;
  3. 确定对象间的相互关系。

  按前面所提,类是具有相同行为对象的模板,通过同一个类创建的不同对象具有相同的行为,对象是类的一个具体例子(实例),我们面向对象设计程序时,一般从类的设计开始。

类的设计

  类通常情况下是自然世界中一个概念的描述,比方说Person类通常对应人,这种软件和自然世界中的对应关系使我们可以尽可能运用人类的自然思维方式去解决问题。那么如何发现类呢?一个最简单的办法就是把我们熟知的自然概念直接抽象为类,比方说一个图书馆借书的程序,管理员,书,借书者,我们可以很容易想出一系列的概念,这些名词概念来自于我们对生活对该领域的了解。把我们熟悉的名词(概念)直接抽象为类,把动词抽象为该类的行为,这是一种最粗糙的类设计方法。这种设计比较容易下手,但是也会出现一些问题:

  1. 实现性,事物分抽象事物和具体事物两种,程序设计中用类的实例(对象)来表示一个具体事物。对于人来说,管理员,借书者都是人,同一个人可以充当不同角色,一个人可以通过学习具备一些能力并且通过经验积累来优化自己的能力。那么如何来设计这样一个类,让该类可以具备责任并自适应变化?
  2. 目的性,现实世界中,解决一个领域的软件总会遇见各种各样的概念,那么需要把这些概念全部抽象为类么?面向对象就是把所有概念全部类化?

  对第一点来说,这是一个理想状态,大多数面向对象语言都是静态语言,如C#/Java/C++等,类作为对象的模板,既确定了该类对象的功能,在编译后又决定了对象的内存模型。静态语言使用继承,接口来完成类的扩展,相比动态语言,静态语言在运行速度,类型安全上有着很大优势,但由于类的扩展性是在编译期决定的,要应对变化就需要在类的设计上多下功夫。

  针对第二点,这个前面已经提到了,引入对象的唯一原因是具有责任,应对变化,让它“活”起来,是为了让我们更轻松的生活,面向对象是一种方法观,程序执行后仍然被编译成一条条的过程语句执行。不要舍本逐末,来总结一下面向对象的设计经验。

设计模式

  设计模式,这里的全称应该是面向对象设计模式,我们熟知的设计模式,通常指GOF定义的23种设计模式。每种模式都有一个对应的名字,按种类可分为创建型,结构型和行为型三类。

  介绍面向对象设计模式的文章也很多,模式,按Alexander的经典定义,指在某一背景下某个问题的一种解决方案。这里的解决方案指细节,某一背景下某个问题才是难点,深刻理解“什么时候,什么场合用”比“如何用”更重要,既然是面向对象设计模式,先从对象创建说起。

  面向对象是为了适应变化,变化无处不在:

  1. 对象的创建要能适应变化,它不会自己凭空跳出来,必须有其他对象来负责该对象的创建。通常用工厂对象(Factory)来负责对象的创建,在工厂的基类中定义创建对象的虚方法,由工厂的子类来具体化这个创建。
  2. 对象间的组织结构要能适应变化,如一般大公司具有总经理-部门经理-项目经理-员工等职位,完成一件事情需要各部门各员工间的配合,混乱的组织结构会导致难以应对扩张,对象间职位不清等问题。
  3. 对象的行为要能适应变化,为了完成责任,变化可能来自于各个方面,可能会受对象状态的影响,可能需要其他对象的协助等等。

  设计模式是一种经验的积累,面向对象设计模式的根本是为了应对对象变化,每种设计模式都对应了一类变化点。这就需要在实际运用中识别变化点,因地制宜的分析可否引入对应的设计模式来最佳化设计。

后记

  文章存在草稿里很久了,再接已经没有思路了,简略了描述一下后面的想法:

  1. 关于面向对象设计的方法:面向对象程序设计仍在发展之中,关于如何指导用户从面向对象角度分析和设计程序,四色原型分析方法,领域驱动建模思想,DCI架构等都是一些好的经验。当然,这些经验都是帮助我们更好的去设计程序的,要因地制宜,不要本末倒置,不看实际就选定了一种方法,再生搬硬套把需求塞进这些框框之中。
  2. 关于面向对象设计的优点:前面列举了面向过程的一些好的经验(模块原则,组合原则,扩展原则等),是因为在很多介绍面向对象程序设计的文章中,往往夸大了面向对象设计的优点。这些好的思想原则是通用的,不仅仅是面向对象设计所独有的。面向对象程序设计的优点在于它契合了人们分析自然时概念化的思维方式,在解决真实生活问题时往往比较容易下手。
  3. 关于面向对象设计的缺点:成也萧何败也萧何,如果我们正确分析了需求,找准了可能的变化点,设计出的类模型往往具有较高的价值。如果错误的假设了程序的逻辑,过细/忽略了可能的变化点,则设计出的程序可能会导致结构混乱,抽象过多/无法扩展等问题。面向对象程序设计多呼吁尽早的引入领域专家帮助分析建模,来防止错误的捏造对象导致事倍功半。
  4. 关于面向对象设计的实践:变化是不断存在的,很难存在所谓的完美设计,即使有领域专家的帮助,也很难做到类完全对修改封闭,对扩展开放。随着开发的深入,重构是不可避免的,这里重构的作用既要适应变化,又要保证已有功能的正确性。关于这方面的实践,敏捷是比较热的词汇,敏捷的主张在于用简单的初始设计,然后小步的持续改进,通过TDD来确保每一步改进的正确性。要应对变化,就要预知变化,设计抽象来隔离变化,当然,过度的抽象也会增加软件的复杂度,一个简单的指导原则是,在不能预知变化或者变化不是十分剧烈前,不要过多设计,清晰胜于一切。
  5. 关于面向对象设计和编程语言:众所周知,C++/JAVA/C#等是面向对象的语言,在语言层次提供了类的支持,但并不是这些面向对象语言写出来的一定是面向对象的程序,比如所谓的充血/贫血模型---对象的行为是否被封装在对象其中,还是由Service来提供。这里出现了很多的名字,DomainObject,ValueObject等等,抛去这些名字不谈,如果对象的行为由对象来提供,那么这个对象才真正“活”起来,否则它还是过程化的数据封装。但并不是这样做不好,面向对象设计不是万能药,错误点“活”了对象,不仅不会让你省心,还会让你更加操心。反过来C语言等面向过程语言也可以支持面向对象的思想,Windows的WNDCLASS就是一个很好的例子,换一个角度去讲,如果程序中出现了依赖倒置,依赖于抽象而不依赖于具体,这种抽象体现出来的就是面向对象的思想。

题外话

  设计方面的话题总是显得空泛,设计能力的提升来自于经验,脱离了实际去谈设计模式无疑纸上谈兵。设计上面对应需求,下面对应编码,实际又为项目服务,受项目资源制约。好的设计来自于坚持和妥协,也许往大了说很多东西也如此,祝朋友们多点积累,少点折腾,谢谢。

 

Illusion = Caliburn.Micro + MEF

2011-07-18 12:05 by 周永恒, 1697 visits, 收藏编辑

前言

  准备使用Caliburn.Micro结合MEF写一个类似于VS2010的IDE框架,支持插件开发,Menu、Toolbar等的可配置性,还有一些功能如:Option,多语言,换肤等。一方面作为技术沉淀,一方面也可以为新入WPF或者对Caliburn.Micro感兴趣的朋友们做一个指导。

  没想到什么太好的名字,项目起名为Illusion,希望不是个幻觉,Shifty。 项目的出发点也不复杂,主要想使用MEF来做插件开发,通过DirectoryCatalog来做插件检查,使用Export/Import构建Menu,Toolbar等。Caliburn.Micro是一个开源框架,框架基于MVVM模式,代码简洁而不简单,是企业级项目开发的一把利器。

实现

  工程目录如下:

WPF插件式框架_第3张图片

  Illusion工程是核心的框架(Framework),Illusion.Demo是使用Illusion的EXE工程,AddIns文件夹下下有一些插件工程,项目使用了开源比较成熟的AvalonDock做停靠窗口。

  运行起来的程序:

WPF插件式框架_第4张图片

  项目提出了两个概念:Part,Screen。如上图所示,Menu和Toolbar的子项称为Part,停靠的窗口Project等称为Screen。

配置

  添加Menu的代码如下:

   1: [MenuPart(BaseMenu = WorkbenchName.WindowPart, PreviousMenu = WorkbenchName.CloseDocumentsPart)]
   2: public class ResetLayoutPart : MenuPart
   3: {
   4:     public ResetLayoutPart()
   5:         : base(WorkbenchName.ResetLayoutPart)
   6:     {
   7:         Icon = "Icons.16x16.CopyIcon";
   8:     }
   9:  
  10:     public override void Execute()
  11:     {
  12:         base.Execute();
  13:     }
  14: }

  第一行的MenuPart继承自ExportAttribute,等同于[Export(typeof(IMenuPart)],BaseMenu和PreviousMenu指定了ResetLayoutPart的父项和它的上一个Menu,以此来确定Menu的位置。当Menu点击时,Execute方法被调用,在此写入Menu的执行代码。可以重载CanExecute来决定Menu是否可调用,设置IsVisible属性来决定Menu是否可见。

  通常情况下,很多Menu同时也会在Toolbar上出现,为了减少重复代码,定义了MenuToolPart类指定该Part既可以是Menu也可以充当Toolbar。

  Screen的添加方法和Part类似,略去不讲。

其他

  可以添加插件工程导出Part或Screen等。

WPF插件式框架_第5张图片

  程序运行后,DirectoryCatalog会监视AddIns目录下所有插件并导入。

  其他一些Option,多语言,换肤功能请参见代码,这里不一一介绍了。

闲聊

  Illusion项目陆陆续续写了一周多,想法变为代码,激情过后都是空虚,闭门造车也需要耐心,这些年业余写了好多代码后来都扔一边去了。

  把代码上传上来和大家交流一下,如果有对这方面感兴趣的朋友欢迎和我联系,也不加什么PL协议了,有不足之处欢迎指正,有能用之处欢迎拿去用。如果真能对您有所帮助的话,希望你能留个言或者顶一下,江湖话说:

做兄弟,要厚道

 

Illusion的代码下载请点击这里,使用了System.Windows.Interactivity,需要Expression Blend4以上版本支持。

 

本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

随笔分类 -WPF之旅

WPF插件式框架

2012-02-16 14:27 by 周永恒, 1137 visits, 网摘收藏编辑
摘要:本文主要介绍了WPF插件式框架的一个思路,代码来自于以前给朋友写的一个Sample,希望能给朋友们带来些帮助。  阅读全文

解析Caliburn.Micro(四)

2011-08-31 10:59 by 周永恒, 1362 visits, 网摘收藏编辑
摘要:继续来介绍Caliburn.Micro框架,主要介绍了Action+Convention这条主线,对WPF/Silverlight/WP7感兴趣的朋友们可以阅读本篇文章。  阅读全文

深入WPF--Style

2011-08-01 12:07 by 周永恒, 2926 visits, 网摘收藏编辑
摘要:继续这个系列,深入介绍WPF中的Style,Silverlight也可以作为参考,希望能在Style这个点上,把它讲透。  阅读全文

解析Caliburn.Micro(三)

2011-07-20 15:43 by 周永恒, 1560 visits, 网摘收藏编辑
摘要:书接前文,前篇文章简略了介绍了一下Caliburn.Micro(简称CM)的Action,这篇文章继续讨论CM的下一个Feature:Convention。  阅读全文

Illusion = Caliburn.Micro + MEF

2011-07-18 12:05 by 周永恒, 1697 visits, 网摘收藏编辑
摘要:准备使用Caliburn.Micro结合MEF写一个类似于VS2010的IDE框架,支持插件开发,Menu、Toolbar等的可配置性,还有一些功能如:Option,多语言,换肤等。一方面作为技术沉淀,一方面也可以为新入WPF或者对Caliburn.Micro感兴趣的朋友们做一个指导。  阅读全文

解析Caliburn.Micro(二)

2011-04-22 11:39 by 周永恒, 2421 visits, 网摘收藏编辑
摘要:Caliburn.Micro是用于WPF,Silverlight,WP7的开源应用框架,本文主要介绍了Caliburn.Micro的Action,希望能给朋友们带来些帮助。  阅读全文

解析Caliburn.Micro(一)

2011-04-18 11:35 by 周永恒, 2866 visits, 网摘收藏编辑
摘要:Caliburn是Codeplex上的一个开源框架,可用于WPF,Silverlight,WP7等,分享一下对于Caliburn.Micro的心得,希望能给朋友们带来点帮助。  阅读全文

WPF企业应用--自实现Binding,可用于WinForm,Web等

2011-03-09 01:29 by 周永恒, 2804 visits, 网摘收藏编辑
摘要:开始写这个新系列,这些年用WPF做了很多项目,杂七杂八的东西写了不少,略略总结下,也希望能给朋友们带来点帮助。 本篇文章主要是自实现了一个BindingEngine,可以在WPF,WinForm,Web等各个情景中使用。  阅读全文

深入WPF -- Dispatcher(补)

2011-01-12 02:59 by 周永恒, 4014 visits, 网摘收藏编辑
摘要:惰性是很可怕的东西,时隔一年多,继续写这个WPF系列,本篇文章继续深入研究WPF的线程和Dispatcher,希望朋友们多多支持。  阅读全文

一站式WPF--Window(一)

2009-11-30 14:18 by 周永恒, 3965 visits, 网摘收藏编辑
摘要:Window是Windows操作系统的核心,本篇文件介绍了WPF中的Window,并简略的介绍了WPF的架构以及如何从WPF对象绘制到屏幕,希望管中窥豹,能一窥WPF的全貌。  阅读全文

一站式WPF--依赖属性(DependencyProperty)二

2009-10-20 11:32 by 周永恒, 5662 visits, 网摘收藏编辑
摘要:书接上文,前篇文章介绍了依赖属性的原理和实现了一个简单的DependencyProperty(DP),这篇文章主要探讨一下如何使用DP以及有哪些需要注意的地方,当然,有不对的地方也欢迎朋友们指正  阅读全文

一站式WPF--依赖属性(DependencyProperty)一

2009-09-10 17:16 by 周永恒, 5793 visits, 网摘收藏编辑
摘要:依赖属性是WPF/Silverlight的核心部分,包括WF也在使用类似的实现,这篇文章介绍了从属性到依赖属性的演变以及依赖属性的原理,欢迎指教。  阅读全文

一站式WPF--线程模型和Dispatcher

2009-08-31 12:13 by 周永恒, 6117 visits, 网摘收藏编辑
摘要:开始着手写这个WPF系列,这里的一站式,就是力争在每一个点上能把它讲透,当然,做不到那么尽善尽美,如果有不对的地方也欢迎朋友们指正,我会逐步补充,争取把这个系列写好。  阅读全文

如何学好WPF

2009-07-31 15:20 by 周永恒, 8528 visits, 网摘收藏编辑
摘要:用了三年多的WPF,开发了很多个WPF的项目,就我自己的经验,谈一谈如何学好WPF,也和朋友们讨论一下如何学好一门新技术,当然,抛砖引玉,如果您有什么建议也希望不吝赐教。  阅读全文

你可能感兴趣的:(WPF)