当前位置:编程学习 > asp >>

WPF基础入门<1>__体系结构

1. WPF基础之体系结构
本主题提供 Windows Presentation Foundation (WPF) 类层次结构的指导教程,涵盖了 WPF 的大部分主要子系统,并描述它们是如何交互的。本主题还详细介绍了 WPF 架构师所做的一些选择。

System.Object

WPF 主要编程模型是通过托管代码公开的。在 WPF 的早期设计阶段,曾有过大量关于如何界定系统的托管组件和非托管组件的争论。CLR 提供一系列的功能,可以令开发效率更高并且更加可靠(包括内存管理、错误处理和通用类型系统等),但这是需要付出代价的。

下图说明了 WPF 的主要组件。关系图的红色部分(PresentationFramework、PresentationCore 和 milcore)是 WPF 的主要代码部分。在这些组件中,只有一个是非托管组件 – milcore。milcore 是以非托管代码编写的,目的是实现与 DirectX 的紧密集成。WPF 中的所有显示是通过 DirectX 引擎完成的,可实现高效的硬件和软件呈现。WPF 还要求对内存和执行进行精确控制。milcore 中的组合引擎受性能影响关系大,需要放弃 CLR 的许多优点来提高性能。

clip_image002

本主题的后面部分将讨论 WPF 的托管和非托管部分之间的通信。下面介绍托管编程模型的其余部分。

System.Threading.DispatcherObject

WPF 中的大多数对象是从 DispatcherObject 派生的,这提供了用于处理并发和线程的基本构造。WPF 基于调度程序实现的消息系统。其工作方式与常见的 Win32 消息泵非常类似;事实上,WPF 调度程序使用 User32 消息执行跨线程调用。

要讨论 WPF 中的并发,首先必须真正理解两个核心概念 – 调度程序和线程关联。

在 WPF 的设计阶段,目标趋向于单一线程的执行,但这不是一种与线程“关联的”模型。当一个组件使用执行线程的标识来存储某种类型的状态时,将发生线程关联。最常见的形式是使用线程本地存储 (TLS) 来存储状态。线程关联要求执行的每个逻辑线程仅由操作系统中的一个物理线程所拥有,这将占用大量内存。最后,WPF 的线程处理模型保持与具有线程关联的单一线程执行的现有 User32 线程处理模型同步。主要原因是互操作性 – 类似于 OLE 2.0 的系统、剪贴板和 Internet Explorer 均需要单一线程关联 (STA) 执行。

假设您具有带有 STA 线程的对象,则需要一种方式来在线程之间通信,并验证您是否位于正确的线程上。调度程序的作用就在于此。调度程序是一个基本的消息调度系统,具有多个按优先级排列的队列。消息的示例包括原始输入通知(鼠标移动)、框架函数(布局)或用户命令(执行此方法)。通过从 DispatcherObject 派生,您可以创建一个具有 STA 行为的 CLR 对象,并在创建时获得一个指向调度程序的指针。

System.Windows.DependencyObject
生成 WPF 时使用的主要体系结构原理之一是首选属性而不是方法或事件。属性是声明性的,使您更方便地指定意图而不是操作。它还支持模型驱动或数据驱动的系统,以显示用户界面内容。这种理念的预期效果是创建您可以绑定到的更多属性,从而更好地控制应用程序的行为。

为了从由属性驱动的系统获得更多,需要一个比 CLR 提供的内容更丰富的属性系统。此丰富性的一个简单示例就是更改通知。为了实现双向绑定,您需要绑定的双方支持更改通知。为了使行为与属性值相关联,您需要在属性值更改时得到通知。Microsoft .NET Framework 具有一个 INotifyPropertyChange 接口,使对象可以发布更改通知(不过,这是可选的)。

WPF 提供一个丰富的属性系统,该属性系统是从 DependencyObject 类型派生的。该属性系统实际是一个“依赖”属性系统,因为它会跟踪属性表达式之间的依赖关系,并在依赖关系更改时自动重新验证属性值。例如,如果您具有一个会继承的属性(如 FontSize),当继承该值的元素的父级发生属性更改时,会自动更新系统。

WPF 属性系统的基础是属性表达式的概念。在 WPF 的第一版中,属性表达式系统是关闭的,表达式都是作为框架的一部分提供的。表达式致使属性系统不具有硬编码的数据绑定、样式调整或继承,而是由框架内后面的层来提供这些功能。

属性系统还提供属性值的稀疏存储。因为对象可以有数十个(如果达不到上百个)属性,并且大部分值处于其默认状态(被继承、由样式设置等),所以并非对象的每个实例都需要具有在该对象上定义的每个属性的完全权重。

属性系统的最后一个新功能是附加属性的概念。WPF 元素是基于组合和组件重用的原则生成的。某些包含元素(如 Grid 布局元素)通常需要子元素上的其他数据才能控制其行为(如行/列信息)。任何对象都可以为任何其他对象提供属性定义,而不是要将所有这些属性与每个元素相关联。这与 JavaScript 中的“expando”功能相似。

System.Windows.Media.Visual

定义一个系统后,下一步是将像素绘制到屏幕上。Visual 类用于生成可视化对象的树,每个对象可以选择性地包含绘制指令以及有关如何呈现这些指令(剪辑、变换等)的元数据。Visual 设计为极其轻量且灵活,所以大部分功能未进行 API 公开,并且极为依赖受保护的回调函数。

Visual 实际上是到 WPF 组合系统的入口点。Visual 是以下两个子系统之间的连接点:托管 API 和非托管 milcore。

WPF 通过遍历由 milcore 管理的非托管数据结构来显示数据。这些结构(称为组合节点)代表层次结构显示树,其中每个节点都有呈现指令。只能通过消息传递协议来访问此树(下图右侧所示)。

当对 WPF 编程时,您将创建 Visual 元素及派生的类型,它们通过此消息传递协议在内部与此组合树进行通信。WPF 中的每个 Visual 可以不创建组合节点,也可以创建一个或多个组合节点。

clip_image004

请注意一个非常重要的体系结构细节 – 可视对象和绘制指令的整个树都要进行缓存。在图形方面,WPF 使用一个保留的呈现系统。这可以使系统以一个高刷新率重绘系统,并且不会发生组合系统阻止对用户代码的回调。这有助于防止出现应用程序无响应的情况。

关系图中不十分引人注意的另一个重要细节是系统实际上如何执行组合。

在 User32 和 GDI 中,系统是在一个即时模式剪辑系统上工作。当需要呈现一个组件时,系统会建立一个剪辑边界,不允许组件接触该边界之外的像素,然后会要求此组件在该框中绘制像素。此系统在内存受限的系统上工作良好,因为当某些内容更改时,只需要处理受影响的组件即可 – 不会有两个组件对一个像素的颜色更改起作用。

WPF 使用“绘画器的算法”绘制模型。这意味着并不是剪辑每个组件,而是要求从显示内容的背面至正面来呈现每个组件。这允许每个组件在先前的组件的显示内容上绘制。此模型的优点是您可以生成部分透明的复杂形状。与现今的现代图形硬件比较,此模型相对要快(创建 User32/ GDI 的情况除外)。

如上面所述,WPF 的一个核心原理是移动到一个更具声明性且“以属性为核心”的编程模型。在可视化系统中,这会表现为需要关注的两种情况。

首先,如果您考虑保留的模式图形系统,则实际上是从命令性 DrawLine/DrawLine 类型模型移动到面向数据的模型 new Line()/new Line()。通过这一向数据驱动的呈现移动,可以在使用属性表达的绘制指令上进行复杂的操作。从 Drawing 派生的类型实际上是用于呈现的对象模型。

第二,如果评估动画系统,您将看到它几乎是完全声明性的。无需要求开发人员计算下一位置或下一颜色,您可以将动画表示为动画对象上的一组属性。于是,这些动画可以表示开发人员或设计人员的意图(在 5 秒内将此按钮从一个位置移动到另一个位置),系统就可以确定完成此任务的最有效方式。

System.Windows.UIElement

UIElement 定义核心子系统,包括 Layout、Input 和 Event。

Layout 是 WPF 中的一个核心概念。在许多系统中,可能有一组固定的布局模型(HTML 支持三种布局模型:流、绝对和表),也可能没有布局模型(User32 实际仅支持绝对定位)。WPF 先假设开发人员和设计人员希望有一个灵活的可扩展布局模型,该模型可能是由属性值而不是命令性逻辑驱动的。在 UIElement 级别,会引入布局的基本协定 - 具有 Measure 和 Arrange 处理过程的两阶段模型。

Measure 允许组件确定它要采用的大小。此阶段独立于 Arrange,因为在许多情形下,父元素会要求子元素测量若干次以确定其最佳位置和大小。父元素要求子元素测量这一事实体现了 WPF 的另一关键原则 – 内容大小。WPF 中的所有控件支持调整到内容原始大小的功能。这使本地化更加容易,并允许在调整大小时对元素进行动态布局。Arrange 阶段允许父元素定位并确定每个子元素的最终大小。

通常会花费大量的时间来讨论 WPF 的输出端(Visual 及其相关对象)。然而,在输

补充:Web开发 , ASP.Net ,
CopyRight © 2022 站长资源库 编程知识问答 zzzyk.com All Rights Reserved
部分文章来自网络,