WPF架构学习总结

预期读者

    1. 初学者。     2. 懒得总结的人。:)     3. 想大致了解WPF框架主要类的功能的人。

前言

    学习WPF也有段时间了,今天把学到的东西整理一下,主要还是学自MSDN。

    下面,我就WPF中最重要的继承线上的几个类列一下,并归纳下它们的功能和使用场景:

Object(托管代码)

    首当其冲的,自然是System.Object类了。这里主要想说的是,WPF的大部分代码都是使用托管代码编写,原因是因为CLR的许多不错的特性(如内存管理、错误处理、通用类型系统等。),可以让开发的程序更有效、更健壮。但是,框架并不是所有代码都是托管的,也有一部分是由非托管代码编写。原因主要是因为WPF是展现层框架,它的显示需要和DirectX很紧密的集成起来,进行硬渲染和软渲染,以得到性能上的提升。

    下面的结构图中,红色部分是属于WPF框架的。其中,只有milcore这个部分是采用非托管代码编写。所以,可以看出,我们在使用WPF的时候,是不会接触到里面的非托管代码的。

DispatcherObject(异步)

    命令空间:System.Threading。     WPF Dispatcher使用User32的消息机制来实现跨线程调用。工作机制类似Win32的消息泵。     WPF的线程模型和User32的线程模型保持一致,使用STA。主要原因是互可操作性,因为现在的很多系统都是需要STA的,如IE、OLE2.0、剪贴板等。     通过Dispatcher,我们可以实现线程间的通信。继承自DispatcherObejct的类,都获取了一个所在线程的Dispatcher引用,这样,任何使用这个类的对象的线程,都可以使用它的Dispatcher来发送“消息”。 一般情况下,我们使用这个类的意图主要是异步线程调用DispatcherObject的Dispather来让DispatcherObject的创建线程做一些特定的事情,如设置界面上某个值。这样大大方便了我们开发人员。想想我原来用WindowsForm开发的时候,为了异步调用显示一下Label,写出来的代码真是够繁琐。

DependencyObject(属性)

    命令空间:System.Windows。      WPF框架中最主要的思想之一是:优先使用属性,而不是事件、方法。     继承自DependencyObject的类,就拥有了WPF特别定制的“富”属性系统。该属性系统提供了以下好处:     1. Dependency Property:“依赖”的属性,自动检测依赖性的属性表达式,当被依赖的属性变化时,自动更新属性值。     2. 使用尽量少的属性值存储空间。因为并不是每一个属性都会存储在内存中。     3. Attached Property:任何一个类都允许使用其它的类定义的任何依赖属性。(类似于javascript的expando特性。)

Visual(集成、绘制)

    命令空间:System.Windows.Media。     Visual类才真正是WPF的入口点。就是在这里,整合了托管代码API和非托管代码milcore。     WPF使用milcore中的一种叫Composition Nodes的数据结构来进行显示。这种数据结构类似一棵树,树的每个节点都带有绘制的指令。Visual以及Visual的子类,可以通过消息协议来和Composition Nodes进行通信。(每一个Visual,可能会建立零到多个不等的Composition Nodes。)重点是:Visual的整棵树及其所附属绘制指令,都会被缓存起来。这样,整个系统可以进行高速的重绘,也不会因为用户程序的阻塞而阻塞显示。     在User32和GDI中,系统是通过一种盒子方式来进行绘制的:每一个成员都被放在一个指定的区域里面进行绘制,然后再叠加再一起。这样生成的图象中的每一个象素,其实都只属于唯一一个成员。但是是WPF系统中,使用的是"painter's algorithm"绘制算法:从后到前,一个一个的画出这些成员。这样的话,后画出来的成员就在已经绘制好的图案上继续进行绘制,就可以显示出一些复杂的半透明的图形。     而“属性优先”的思想,在Visual类中也有所体现。如,我们原来熟悉的DrawLine()/DrawLine()方式,现在变成了new Line()/new Line()。这种数据驱动的编程方式,可以让我们使用属性来完成一些复杂的绘制操作。又如,动画的使用方式,也是完全的使用属性声明方式。

UIElement(界面基础)

    命令空间:System.Windows。

    UIElement提供了很多PresentationCore程序集中比较重要的特性:

1. 布局:     布局系统中,比较重要的是MeasureArrage这两个阶段。     Measure过程让一个成员决定它到底需要多大的尺寸。很多情况下,父元素经常会多次询问子元素所需要的尺寸,然后再决定给它一个比较合适的最终尺寸。这就是WPF中另一个重要思想:Size To Content。这样,WPF中所有的控件,都可以控制自己的显示尺寸,使其大小和控件的内容比较协调。

2. 输入、事件:     在WPF中事件模型中最基本的、不同于以往应用程序的变化是“事件路由模型”。操作系统收到从硬件发出的输入信号后,导向相应的进程、线程。当这些关于输入信息的Win32消息被传送到WPF中时,会被转换成WPF最原始的输入信号并发送到Dispatcher“发报机”中。WPF可能会把一个原始的信号转换成多个与之相应的事件。     这里需要说一下,这里事件路由的概念。每个输入发生时,会被转换成两个具体的事件,一个preview event和一个一般事件。一个事件从控件树上发生事件的目标节点,依次传到最上层的根节点的方式,叫作“bubble”。另一种相反的方式被叫作“tunnel”。preview event就是一个正在进行tunnel的事件。这样,可以先让所有元素都有机会对事件进行过滤,或者发生一些特定的行为。然后这个事件又被从目标节点依次bubble回到根节点。     另外,不象Win32中的应用程序只有一个"TranslateAccelerator"(用来控制如“Ctrl+N”这样的组合键),因为WPF系统是“组合”而成的,所以其中的每一个元素都可以通过bubble event和tunnel event来定制自己的"TranslateAccelerator"。     UIElement实现了IInputElement接口,这个接口中定义了很多我们所熟悉的事件,如KeyDown、MouseMove等。:)

3. 命令绑定:     UIElement中还引入了Command Binding的概念。Command可以理解为一个较高级的事件。:)InputGesture 和ICommand都被设计为有着良好的扩展性,在使用的时候,我们可以通过命令绑定而把它们绑定在一起。

4. 动画:     UIElement作为比较底层的API类,实现了接口IAnimatable,为上层提供了基本的动画API。上层类可以在这些基本操作上扩展更加易用、强大的功能。

FrameworkElement(?)

    命令空间:System.Windows。

1. FrameworkElement在UIElement提供的布局基础上,增加了layout "slot"的概念。可以让布局人员更简单的使用属性的语法来定义布局。 2. FrameworkElement还提供了更易用的API,如可以使用BeginStoryboard方法,而不是UIElement中的BeginAnimation。 3. Binding:类似WinForm和ASP.NET,WPF全面支持属性绑定、转换、列表绑定等。其中比较新的概念是数据模板,它能让你以XML的方式来指定数据如何被展示。它不再是由你去写一个直接绑定数据的界面,而是让数据自己来决定如果显示。 4. 样式:可以理解为:WPF支持为一些通用的属性进行独立的定义,然后再绑定到需要的元素上。可以为某一元素指定使用这些样式,也可以直接把样式绑定到某一类元素上。

Control(模板)

    命令空间:System.Windows.Controls。

1. Control中最重要的功能就是模板的使用。说白了,其实模板就是使用属性声明的方式来为Control的属性设置孩子元素集合2. 还定义了一些如前景色、背景色、内容对齐方式等的简单属性。 3. Control运行交互模型和数据模型。交互模型中定义命令并绑定到动作上,数据模型提供许多属性来定义交互模型、显示。使用数据模板(属性)、交互模板(命令、事件)、显示模板(模板)可以让开发人员完全定制Control的外观和行为。 4. 另外,控件数据模型中一个新的概念叫:Content Model。例如Button的Content不再只是简单的字符串类型,而是Object类型,可以是一个特定的显示对象。

总结

    了解这些类,可以让我们可以选择在适当的抽象层次上进行编程。不过暂时体会还不深,所以还不知道给FrameworkElement的那个总结性的括号里,填写一个什么词比较合适。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏听雨堂

子线程调用UI线程的方法

vs2005中,子线程不允许使用UI中的控件,网上的解决方法都有:使用控件的Invoke,不过在我自己的应用中总觉得麻烦:我要从子线程中调用一个主线程中的处理...

21480
来自专栏happyJared

Intellij IDEA 神器那些让人爱不释手的小技巧

在2018年5月6日写了一篇介绍IntellIJ IDEA的文章,Intellij IDEA神器居然还有这些小技巧,主要是列出一些平时大家可能没用过或者没怎么用...

16220
来自专栏平凡文摘

Intellij IDEA 那些隐藏好用的小技巧

20340
来自专栏Java技术栈

Intellij IDEA 那些隐藏好用的小技巧

之前写了一篇介绍IntellIJ IDEA的文章《 Intellij Idea非常6的10个姿势 》,主要是列出一些平时大家可能没用过或者没怎么用,但是又非常好...

12440
来自专栏Java进阶架构师

Intellij IDEA神器那些让人爱不释手的小技巧

之前写了一篇介绍IntellIJ IDEA的文章,主要是列出一些平时大家可能没用过或者没怎么用,但是又非常好用的IntellIJ IDEA小技巧。由于篇幅原因,...

11210
来自专栏java思维导图

Intellij IDEA神器那些让人爱不释手的14种小技巧,统统告诉你!

来源:https://blog.csdn.net/linsongbin1/article/details/80560332

10450
来自专栏腾讯NEXT学位

Vue.js最佳实践(五招让你成为Vue.js大师)

59470
来自专栏逸鹏说道

Jupyter ~ 像写文章般的 Coding

这次选Markdown模式(关于Markdown基础可以看之前写的Markdown Base)

13230
来自专栏React

React和Redux——状态管理Flux和Redux

在强调组件化的React中,我们需要以高内聚、低耦合的原则设计高可复用性的组件。因此渲染组件的数据由两部分组成,一个是由父组件传入的Props参数、一个是组件的...

28770
来自专栏圣杰的专栏

Asp.net mvc 知多少(六)

本系列主要翻译自《ASP.NET MVC Interview Questions and Answers 》- By Shailendra Chauhan,想...

26250

扫码关注云+社区

领取腾讯云代金券