WPF 体系结构WPF Architecture

本主题提供 Windows Presentation Foundation (WPF)类层次结构的指导教程。This topic provides a guided tour of the Windows Presentation Foundation (WPF) class hierarchy. 它涵盖了 WPF 的大部分主要子系统,并描述了它们的交互方式。It covers most of the major subsystems of WPF, and describes how they interact. 它还详细介绍了 WPF 架构师所做的一些选择。It also details some of the choices made by the architects of WPF.

System.ObjectSystem.Object

主要的 WPF 编程模型通过托管代码公开。The primary WPF programming model is exposed through managed code. 在 WPF 设计阶段的初期,会有许多辩论,其中应该在系统的托管组件和非托管组件之间绘制线条。Early in the design phase of WPF there were a number of debates about where the line should be drawn between the managed components of the system and the unmanaged ones. CLR 提供了许多功能,这些功能使得开发更高效、更可靠(包括内存管理、错误处理、通用类型系统等),但会产生费用。The CLR provides a number of features that make development more productive and robust (including memory management, error handling, common type system, etc.) but they come at a cost.

下图演示了 WPF 的主要组件。The major components of WPF are illustrated in the figure below. 关系图(PresentationFramework、PresentationCore 和 milcore)的红色部分是 WPF 的主要代码部分。The red sections of the diagram (PresentationFramework, PresentationCore, and milcore) are the major code portions of WPF. 在这些组件中,只有一个是非托管组件 - milcore。Of these, only one is an unmanaged component – milcore. Milcore 以非托管代码编写,以便实现与 DirectX 的紧密集成。Milcore is written in unmanaged code in order to enable tight integration with DirectX. WPF 中的所有显示都是通过 DirectX 引擎完成的,因此可以实现高效的硬件和软件呈现。All display in WPF is done through the DirectX engine, allowing for efficient hardware and software rendering. WPF 还要求对内存和执行进行精细控制。WPF also required fine control over memory and execution. Milcore 中的组合引擎对性能的影响非常高,需要具有 CLR 的许多优点才能获得性能。The composition engine in milcore is extremely performance sensitive, and required giving up many advantages of the CLR to gain performance.

WPF 在 .NET Framework 中的位置。The position of WPF within the .NET Framework.

在本主题的后面部分将讨论 WPF 的托管和非托管部分之间的通信。Communication between the managed and unmanaged portions of WPF is discussed later in this topic. 下面介绍托管编程模型的其余部分。The remainder of the managed programming model is described below.

System.Threading.DispatcherObjectSystem.Threading.DispatcherObject

WPF 中的大多数对象都派生自 DispatcherObject,后者提供了用于处理并发和线程处理的基本构造。Most objects in WPF derive from DispatcherObject, which provides the basic constructs for dealing with concurrency and threading. WPF 基于调度程序实现的消息传递系统。WPF is based on a messaging system implemented by the dispatcher. 这非常类似于熟悉的 Win32 消息泵;事实上,WPF 调度程序使用 User32 消息执行跨线程调用。This works much like the familiar Win32 message pump; in fact, the WPF dispatcher uses User32 messages for performing cross thread calls.

在 WPF 中讨论并发时,有两个核心概念需要了解,即调度程序和线程关联。There are really two core concepts to understand when discussing concurrency in WPF – the dispatcher and thread affinity.

在 WPF 的设计阶段,目标是迁移到单个执行线程,而不是一个线程的 "关联" 模型。During the design phase of WPF, the goal was to move to a single thread of execution, but a non-thread "affinitized" model. 当一个组件使用执行线程的标识来存储某种类型的状态时,将发生线程关联。Thread affinity happens when a component uses the identity of the executing thread to store some type of state. 最常见的形式是使用线程本地存储 (TLS) 来存储状态。The most common form of this is to use the thread local store (TLS) to store state. 线程关联要求执行的每个逻辑线程仅由操作系统中的一个物理线程所拥有,这将占用大量内存。Thread affinity requires that each logical thread of execution be owned by only one physical thread in the operating system, which can become memory intensive. 最后,WPF 的线程处理模型通过线程关联与单一线程执行的现有 User32 线程处理模型保持同步。In the end, WPF’s threading model was kept in sync with the existing User32 threading model of single threaded execution with thread affinity. 这种情况的主要原因是互操作性-OLE 2.0、剪贴板和 Internet Explorer 等系统都需要单线程关联(STA)执行。The primary reason for this was interoperability – systems like OLE 2.0, the clipboard, and Internet Explorer all require single thread affinity (STA) execution.

假设你具有带有 STA 线程的对象,则需要在线程之间通信并验证你是否位于正确的线程上的一种方法。Given that you have objects with STA threading, you need a way to communicate between threads, and validate that you are on the correct thread. 调度程序的作用就在于此。Herein lies the role of the dispatcher. 调度程序是一个基本的消息调度系统,具有多个按优先顺序排列的队列。The dispatcher is a basic message dispatching system, with multiple prioritized queues. 消息的示例包括原始输入通知(鼠标移动)、框架函数(布局)或用户命令(执行此方法)。Examples of messages include raw input notifications (mouse moved), framework functions (layout), or user commands (execute this method). 通过从 DispatcherObject派生,你可以创建一个具有 STA 行为的 CLR 对象,并在创建时为其提供指向调度程序的指针。By deriving from DispatcherObject, you create a CLR object that has STA behavior, and will be given a pointer to a dispatcher at creation time.

System.Windows.DependencyObjectSystem.Windows.DependencyObject

构建 WPF 时使用的一个主要体系结构理念是对方法或事件的属性的首选项。One of the primary architectural philosophies used in building WPF was a preference for properties over methods or events. 属性具有声明性,可更方便地指定用途而不是操作。Properties are declarative and allow you to more easily specify intent instead of action. 它还支持模型驱动或数据驱动的系统,以显示用户界面内容。This also supported a model driven, or data driven, system for displaying user interface content. 这种理念的预期效果是创建更多可以绑定到的属性,从而更好地控制应用程序的行为。This philosophy had the intended effect of creating more properties that you could bind to, in order to better control the behavior of an application.

为了获得更多由属性驱动的系统,需要的属性系统比 CLR 提供的更多。In order to have more of the system driven by properties, a richer property system than what the CLR provides was needed. 这种丰富性的一个简单示例是更改通知。A simple example of this richness is change notifications. 若要实现双向绑定,需要绑定的双方支持更改通知。In order to enable two way binding, you need both sides of the bind to support change notification. 若要使行为与属性值相关联,需要在属性值更改时收到通知。In order to have behavior tied to property values, you need to be notified when the property value changes. Microsoft .NET 框架有一个接口INotifyPropertyChange,该接口允许对象发布更改通知,但是它是可选的。The Microsoft .NET Framework has an interface, INotifyPropertyChange, which allows an object to publish change notifications, however it is optional.

WPF 提供了更丰富的属性系统,它派生自 DependencyObject 类型。WPF provides a richer property system, derived from the DependencyObject type. 该属性系统实际是一个“依赖”属性系统,因为它会跟踪属性表达式之间的依赖关系,并在依赖关系更改时自动重新验证属性值。The property system is truly a "dependency" property system in that it tracks dependencies between property expressions and automatically revalidates property values when dependencies change. 例如,如果你有一个继承的属性(如 FontSize),则在继承值的元素的父级上更改该属性时,系统会自动更新。For example, if you have a property that inherits (like FontSize), the system is automatically updated if the property changes on a parent of an element that inherits the value.

WPF 属性系统的基础是属性表达式的概念。The foundation of the WPF property system is the concept of a property expression. 在 WPF 的第一个版本中,属性表达式系统是关闭的,表达式都作为框架的一部分提供。In this first release of WPF, the property expression system is closed, and the expressions are all provided as part of the framework. 表达式致使属性系统不具有数据绑定、样式调整或继承硬编码,而是由框架内后面的层来提供这些功能。Expressions are why the property system doesn’t have data binding, styling, or inheritance hard coded, but rather provided by later layers within the framework.

属性系统还提供属性值的稀疏存储。The property system also provides for sparse storage of property values. 因为对象可能有数十个(如果达不到上百个)属性,并且大部分值处于其默认状态(被继承、由样式设置等),所以并非对象的每个实例都需要具有在其上定义的每个属性的完全权重。Because objects can have dozens (if not hundreds) of properties, and most of the values are in their default state (inherited, set by styles, etc.), not every instance of an object needs to have the full weight of every property defined on it.

属性系统的最后一个新功能是附加属性的概念。The final new feature of the property system is the notion of attached properties. WPF 元素基于组合和组件重用的原则构建。WPF elements are built on the principle of composition and component reuse. 通常情况下,一些包含元素(如 Grid layout 元素)需要对子元素的其他数据来控制其行为(如行/列信息)。It is often the case that some containing element (like a Grid layout element) needs additional data on child elements to control its behavior (like the Row/Column information). 任何对象都可以为任何其他对象提供属性定义,而不是将所有这些属性与每个元素相关联。Instead of associating all of these properties with every element, any object is allowed to provide property definitions for any other object. 这与 JavaScript 中的“expando”功能相似。This is similar to the "expando" features of JavaScript.

System.Windows.Media.VisualSystem.Windows.Media.Visual

定义一个系统后,下一步是将像素绘制到屏幕上。With a system defined, the next step is getting pixels drawn to the screen. Visual 类可用于生成视觉对象的树,每个对象都可以有选择性地包含绘制说明以及有关如何呈现这些说明的元数据(剪辑、转换等)。The Visual class provides for building a tree of visual objects, each optionally containing drawing instructions and metadata about how to render those instructions (clipping, transformation, etc.). Visual 旨在实现非常轻量且灵活,因此,大多数功能都没有公共 API 泄露,并且很大程度上依赖于受保护的回调函数。Visual is designed to be extremely lightweight and flexible, so most of the features have no public API exposure and rely heavily on protected callback functions.

Visual 实际上是 WPF 组合系统的入口点。Visual is really the entry point to the WPF composition system. Visual 是这两个子系统之间的连接点,即托管 API 和非托管 milcore。Visual is the point of connection between these two subsystems, the managed API and the unmanaged milcore.

WPF 通过遍历由 milcore 管理的非托管数据结构来显示数据。WPF displays data by traversing the unmanaged data structures managed by the milcore. 这些结构(称为组合节点)代表层次结构显示树,其中每个节点都有呈现指令。These structures, called composition nodes, represent a hierarchical display tree with rendering instructions at each node. 只能通过消息传递协议来访问此树(如下图右侧所示)。This tree, illustrated on the right hand side of the figure below, is only accessible through a messaging protocol.

编程 WPF 时,可以创建 Visual 元素和派生类型,这些派生类型在内部通过此消息传递协议与组合树进行通信。When programming WPF, you create Visual elements, and derived types, which internally communicate to the composition tree through this messaging protocol. WPF 中的每个 Visual 可以创建一个、无或多个组合节点。Each Visual in WPF may create one, none, or several composition nodes.

Windows Presentation Foundation 的可视化树。The Windows Presentation Foundation Visual Tree.

请注意一个非常重要的体系结构细节 - 会缓存整个可视化树和绘制指令。There is a very important architectural detail to notice here – the entire tree of visuals and drawing instructions is cached. 在图形术语中,WPF 使用保留渲染系统。In graphics terms, WPF uses a retained rendering system. 这可以实现以高刷新率重绘系统,并且组合系统不会阻止对用户代码的回调。This enables the system to repaint at high refresh rates without the composition system blocking on callbacks to user code. 这有助于防止出现应用程序无响应的情况。This helps prevent the appearance of an unresponsive application.

关系图中容易忽略的另一个重要细节是系统实际执行组合的方式。Another important detail that isn’t really noticeable in the diagram is how the system actually performs composition.

在 User32 和 GDI 中,系统在即时模式剪辑系统上工作。In User32 and GDI, the system works on an immediate mode clipping system. 当需要绘制一个组件时,系统会建立一个剪裁边界,在此边界外,不允许组件接触像素,然后会要求组件在该框中绘制像素。When a component needs to be rendered, the system establishes a clipping bounds outside of which the component isn’t allowed to touch the pixels, and then the component is asked to paint pixels in that box. 此系统在内存受限的系统上工作良好,因为当某些内容更改时,只需处理受影响的组件即可 - 不会由两个组件同时处理一个像素的颜色。This system works very well in memory constrained systems because when something changes you only have to touch the affected component – no two components ever contribute to the color of a single pixel.

WPF 使用 "刷" 算法绘制模型。WPF uses a "painter's algorithm" painting model. 要求每个组件从显示内容的背面绘制到正面,而不是剪裁每个组件。This means that instead of clipping each component, each component is asked to render from the back to the front of the display. 这允许每个组件在先前组件的显示内容上绘制。This allows each component to paint over the previous component's display. 此模型的优点是可以生成部分透明的复杂形状。The advantage of this model is that you can have complex, partially transparent shapes. 在当今的新式图形硬件中,此模型的速度相对较快(这种情况并不是在创建 User32/GDI 的情况下)。With today’s modern graphics hardware, this model is relatively fast (which wasn’t the case when User32/ GDI were created).

如前文所述,WPF 的核心理念是转向更具说明性的、"以属性为中心" 的编程模型。As mentioned previously, a core philosophy of WPF is to move to a more declarative, "property centric" model of programming. 在可视化系统中,这体现在有意思的几个方面。In the visual system, this shows up in a couple of interesting places.

首先,对于保留的模式图形系统,这实际上是从命令性 DrawLine/DrawLine 类型模型移动到面向数据的模型 new Line()/new Line()。First, if you think about the retained mode graphic system, this is really moving away from an imperative DrawLine/DrawLine type model, to a data oriented model – new Line()/new Line(). 通过这种向数据驱动的绘制的移动,可以使用属性表达绘制指令上的复杂操作。This move to data driven rendering allows complex operations on the drawing instructions to be expressed using properties. 派生自 Drawing 的类型实际上是用于呈现的对象模型。The types deriving from Drawing are effectively the object model for rendering.

第二,如果评估动画系统,你会发现它几乎是完全声明性的。Second, if you evaluate the animation system, you'll see that it is almost completely declarative. 可以将动画表示为动画对象上的一组属性,无需要求开发人员计算下一个位置或下一个颜色。Instead of requiring a developer to compute the next location, or next color, you can express animations as a set of properties on an animation object. 这些动画可以表达开发人员或设计人员的意图(在 5 秒内将此按钮从一个位置移动到另一个位置),系统可以确定完成此任务的最高效方式。These animations can then express the intent of the developer or designer (move this button from here to there in 5 seconds), and the system can determine the most efficient way to accomplish that.

System.Windows.UIElementSystem.Windows.UIElement

UIElement 定义包括布局、输入和事件在内的核心子系统。UIElement defines core subsystems including Layout, Input, and Events.

布局是 WPF 中的核心概念。Layout is a core concept in WPF. 在许多系统中,可能有一组固定的布局模型(HTML 支持三种布局模型:流、绝对和表),也可能没有布局模型(User32 实际仅支持绝对定位)。In many systems there is either a fixed set of layout models (HTML supports three models for layout; flow, absolute, and tables) or no model for layout (User32 really only supports absolute positioning). WPF 开始时假设开发人员和设计人员需要灵活的可扩展布局模型,这种模型可能由属性值而不是命令式逻辑驱动。WPF started with the assumption that developers and designers wanted a flexible, extensible layout model, which could be driven by property values rather than imperative logic. UIElement 级别,会引入布局的基本协定–两阶段模型,其中包含 MeasureArrangeAt the UIElement level, the basic contract for layout is introduced – a two phase model with Measure and Arrange passes.

Measure 允许组件确定要采用的大小。Measure allows a component to determine how much size it would like to take. 这是与 Arrange 分离的阶段,因为在很多情况下,父元素会请求子元素多次测量,以确定其最佳位置和大小。This is a separate phase from Arrange because there are many situations where a parent element will ask a child to measure several times to determine its optimal position and size. 父元素要求子元素测量的事实表明,WPF 的另一个关键理念–内容大小。The fact that parent elements ask child elements to measure demonstrates another key philosophy of WPF – size to content. WPF 中的所有控件都支持调整其内容自然大小的能力。All controls in WPF support the ability to size to the natural size of their content. 这使本地化更加容易,并可实现调整内容大小时进行动态元素布局。This makes localization much easier, and allows for dynamic layout of elements as things resize. Arrange 阶段允许父项定位并确定每个子级的最终大小。The Arrange phase allows a parent to position and determine the final size of each child.

很长时间与 WPF 的输出端(Visual 和相关对象)有关。A lot of time is often spent talking about the output side of WPF – Visual and related objects. 然而,在输入端也有许多创新。However there is a tremendous amount of innovation on the input side as well. 对于 WPF 的输入模型而言,最基本的更改可能是一致的模型,输入事件通过系统进行路由。Probably the most fundamental change in the input model for WPF is the consistent model by which input events are routed through the system.

输入是作为内核模式设备驱动程序上的信号发出的,并通过涉及 Windows 内核和 User32 的复杂过程路由到正确的进程和线程。Input originates as a signal on a kernel mode device driver and gets routed to the correct process and thread through an intricate process involving the Windows kernel and User32. 将对应于输入的 User32 消息路由到 WPF 后,它将转换为 WPF 原始输入消息并发送到调度程序。Once the User32 message corresponding to the input is routed to WPF, it is converted into a WPF raw input message and sent to the dispatcher. WPF 允许将原始输入事件转换为多个实际事件,从而能够在系统的最低级别实现 "MouseEnter" 等功能,并提供有保证的传递。WPF allows for raw input events to be converted to multiple actual events, enabling features like "MouseEnter" to be implemented at a low level of the system with guaranteed delivery.

每个输入事件至少会转换为两个事件 -“预览”事件和实际事件。Each input event is converted to at least two events – a "preview" event and the actual event. WPF 中的所有事件都具有通过元素树路由的概念。All events in WPF have a notion of routing through the element tree. 如果事件从目标向上遍历到根,则称为 "冒泡"; 如果从根开始向下遍历到目标,则称为 "隧道"。Events are said to "bubble" if they traverse from a target up the tree to the root, and are said to "tunnel" if they start at the root and traverse down to a target. 输入预览事件隧道,使树中的任何元素都有机会筛选事件或对事件采取操作。Input preview events tunnel, enabling any element in the tree an opportunity to filter or take action on the event. 然后,常规(非预览)事件将从目标向上浮升到根。The regular (non-preview) events then bubble from the target up to the root.

隧道和浮升阶段之间的划分使键盘快捷键等功能的实现在复合环境中采用一致的方式。This split between the tunnel and bubble phase makes implementation of features like keyboard accelerators work in a consistent fashion in a composite world. 在 User32 中,可以通过使用一个全局表来实现键盘快捷键,该表中包含你希望支持的所有快捷键(Ctrl+N 映射到“新建”)。In User32 you would implement keyboard accelerators by having a single global table containing all the accelerators you wanted to support (Ctrl+N mapping to "New"). 在应用程序的调度程序中,可以调用 TranslateAccelerator,它会探查 User32 中的输入消息,并确定是否有任何消息与已注册的快捷键匹配。In the dispatcher for your application you would call TranslateAccelerator which would sniff the input messages in User32 and determine if any matched a registered accelerator. 在 WPF 中,这不起作用,因为系统完全是 "可组合的"-任何元素都可以处理和使用任何键盘快捷键。In WPF this wouldn’t work because the system is fully "composable" – any element can handle and use any keyboard accelerator. 将此两阶段模型用于输入,可允许组件实现其自己的“TranslateAccelerator”。Having this two phase model for input allows components to implement their own "TranslateAccelerator".

为了进一步执行此步骤,UIElement 还介绍了 CommandBindings 的概念。To take this one step further, UIElement also introduces the notion of CommandBindings. WPF 命令系统允许开发人员根据命令终结点(实现 ICommand的内容)定义功能。The WPF command system allows developers to define functionality in terms of a command end point – something that implements ICommand. 命令绑定使元素可以定义输入笔势 (Ctrl+N) 和命令(“新建”)之间的映射。Command bindings enable an element to define a mapping between an input gesture (Ctrl+N) and a command (New). 输入笔势和命令定义都是可扩展的,并且可以在使用时联系到一起。Both the input gestures and command definitions are extensible, and can be wired together at usage time. 这使得一些操作(例如,允许最终用户自定义其要在应用程序内使用的键绑定)显得无关紧要。This makes it trivial, for example, to allow an end user to customize the key bindings that they want to use within an application.

在本主题中,WPF 的 "核心" 功能-PresentationCore 程序集中实现的功能已成为焦点。To this point in the topic, "core" features of WPF – features implemented in the PresentationCore assembly, have been the focus. 构建 WPF 时,基础组件(如与度量值排列布局的协定)和框架块(如 Grid的特定布局的实现)之间的完全分离是所需的结果。When building WPF, a clean separation between foundational pieces (like the contract for layout with Measure and Arrange) and framework pieces (like the implementation of a specific layout like Grid) was the desired outcome. 目标是提供在堆栈中处于较低位置的可扩展性点,这将允许外部开发人员在需要时创建自己的框架。The goal was to provide an extensibility point low in the stack that would allow external developers to create their own frameworks if needed.

System.Windows.FrameworkElementSystem.Windows.FrameworkElement

可以通过两种不同的方式查看 FrameworkElementFrameworkElement can be looked at in two different ways. 它在 WPF 的较低层中引入的子系统上引入了一组策略和自定义项。It introduces a set of policies and customizations on the subsystems introduced in lower layers of WPF. 它还引入了一组新的子系统。It also introduces a set of new subsystems.

FrameworkElement 引入的主要策略围绕应用程序布局。The primary policy introduced by FrameworkElement is around application layout. FrameworkElementUIElement 引入的基本布局约定为基础,并添加布局 "槽" 的概念,这使得布局作者可以更轻松地使用一致的属性驱动布局语义集。FrameworkElement builds on the basic layout contract introduced by UIElement and adds the notion of a layout "slot" that makes it easier for layout authors to have a consistent set of property driven layout semantics. HorizontalAlignmentVerticalAlignmentMinWidthMargin 等属性(几个属性)将从布局容器内 FrameworkElement 一致的行为中获得派生的所有组件。Properties like HorizontalAlignment, VerticalAlignment, MinWidth, and Margin (to name a few) give all components derived from FrameworkElement consistent behavior inside of layout containers.

FrameworkElement 还可以更轻松地将 API 公开给 WPF 核心层中的许多功能。FrameworkElement also provides easier API exposure to many features found in the core layers of WPF. 例如,FrameworkElement 通过 BeginStoryboard 方法提供对动画的直接访问。For example, FrameworkElement provides direct access to animation through the BeginStoryboard method. Storyboard 提供了一种针对一组属性编写多个动画的脚本的方法。A Storyboard provides a way to script multiple animations against a set of properties.

FrameworkElement 介绍的两个最关键的方面是数据绑定和样式。The two most critical things that FrameworkElement introduces are data binding and styles.

对于已使用 Windows 窗体或 ASP.NET 创建应用程序 用户界面 (UI)user interface (UI)的任何人而言,WPF 中的数据绑定子系统应相对较为熟悉。The data binding subsystem in WPF should be relatively familiar to anyone that has used Windows Forms or ASP.NET for creating an application 用户界面 (UI)user interface (UI). 在上述每个系统中,可通过一种简单的方式来表达希望将给定元素中的一个或多个属性绑定到一个数据片段。In each of these systems, there is a simple way to express that you want one or more properties from a given element to be bound to a piece of data. WPF 完全支持属性绑定、转换和列表绑定。WPF has full support for property binding, transformation, and list binding.

WPF 中数据绑定的最有趣的功能之一是引入数据模板。One of the most interesting features of data binding in WPF is the introduction of data templates. 利用数据模板,可以通过声明方式指定某个数据片断的可视化方式。Data templates allow you to declaratively specify how a piece of data should be visualized. 无需创建可绑定到数据的自定义用户界面,而是转而让数据来确定要创建的显示内容。Instead of creating a custom user interface that can be bound to data, you can instead turn the problem around and let the data determine the display that will be created.

样式实际上是轻量型的数据绑定。Styling is really a lightweight form of data binding. 使用样式,可以将共享定义的一组属性绑定到元素的一个或多个实例。Using styling you can bind a set of properties from a shared definition to one or more instances of an element. 样式通过显式引用(通过设置 Style 属性)或通过将样式与元素的 CLR 类型关联来隐式应用于元素。Styles get applied to an element either by explicit reference (by setting the Style property) or implicitly by associating a style with the CLR type of the element.

System.Windows.Controls.ControlSystem.Windows.Controls.Control

控件的最重要功能是模板化。Control’s most significant feature is templating. 如果将 WPF 的组合系统视为一个保留模式绘制系统,则控件可通过模板化以一种参数化的声明性方式描述其绘制。If you think about WPF’s composition system as a retained mode rendering system, templating allows a control to describe its rendering in a parameterized, declarative manner. ControlTemplate 实际上只是一个脚本,用于创建一组子元素,并将绑定到控件提供的属性。A ControlTemplate is really nothing more than a script to create a set of child elements, with bindings to properties offered by the control.

Control 提供了一组常用属性(ForegroundBackgroundPadding)来命名几个模板,然后模板作者可以使用这些属性自定义控件的显示。Control provides a set of stock properties, Foreground, Background, Padding, to name a few, which template authors can then use to customize the display of a control. 控件的实现提供了数据模型和交互模型。The implementation of a control provides a data model and interaction model. 交互模型定义了一组命令(如窗口的“关闭”),以及到输入笔势的绑定(如单击窗口右上角的红叉)。The interaction model defines a set of commands (like Close for a window) and bindings to input gestures (like clicking the red X in the upper corner of the window). 数据模型提供了一组属性,用于自定义交互模型或自定义显示内容(由模板确定)。The data model provides a set of properties to either customize the interaction model or customize the display (determined by the template).

数据模型(属性)、交互模型(命令和事件)及显示模型(模板)之间的划分,可实现对控件的外观和行为的完全自定义。This split between the data model (properties), interaction model (commands and events), and display model (templates) enables complete customization of a control’s look and behavior.

最常见的控件数据模型是内容模型。A common aspect of the data model of controls is the content model. 如果你查看类似 Button的控件,你会看到它有一个类型为 "Content" 的属性 ObjectIf you look at a control like Button, you will see that it has a property named "Content" of type Object. 在 Windows 窗体和 ASP.NET 中,此属性通常是一个字符串,但它限制了可放入按钮中的内容的类型。In Windows Forms and ASP.NET, this property would typically be a string – however that limits the type of content you can put in a button. 按钮的内容可以是简单的字符串、复杂的数据对象或整个元素树。Content for a button can either be a simple string, a complex data object, or an entire element tree. 如果是数据对象,可以使用数据模板构造显示内容。In the case of a data object, the data template is used to construct a display.

摘要Summary

WPF 旨在使您能够创建动态数据驱动的表示系统。WPF is designed to allow you to create dynamic, data driven presentation systems. 系统的每一部分均可通过驱动行为的属性集来创建对象。Every part of the system is designed to create objects through property sets that drive behavior. 数据绑定是系统的基础部分,在每一层中均进行了集成。Data binding is a fundamental part of the system, and is integrated at every layer.

传统的应用程序创建一个显示内容,然后绑定到某些数据。Traditional applications create a display and then bind to some data. 在 WPF 中,关于控件的所有内容都是由某种类型的数据绑定生成的。In WPF, everything about the control, every aspect of the display, is generated by some type of data binding. 通过在按钮内部创建复合控件并将其显示内容绑定到按钮的内容属性,会显示按钮中的文本。The text found inside a button is displayed by creating a composed control inside of the button and binding its display to the button’s content property.

开始开发基于 WPF 的应用程序时,应该非常熟悉。When you begin developing WPF based applications, it should feel very familiar. 可以设置属性、使用对象和数据绑定,其方式与使用 Windows 窗体或 ASP.NET 的方式大致相同。You can set properties, use objects, and data bind in much the same way that you can using Windows Forms or ASP.NET. 通过更深入地调查 WPF 的体系结构,你会发现创建更丰富的应用程序的可能性,这些应用程序在本质上将数据视为应用程序的核心驱动程序。With a deeper investigation into the architecture of WPF, you'll find that the possibility exists for creating much richer applications that fundamentally treat data as the core driver of the application.

另请参阅See also