标记扩展和 XAML

更新:2007 年 11 月

本主题介绍可扩展应用程序标记语言 (XAML) 的标记扩展概念,包括其语法规则、用途以及底层的类对象模型。

本主题包括下列各节。

  • XAML 处理器和标记扩展
  • 基本标记扩展语法
  • 特定于 WPF 的标记扩展
  • XAML 定义的标记扩展
  • 有关标记扩展语法的更多信息
  • 相关主题

XAML 处理器和标记扩展

XAML 处理器是指可根据其规范(通过编译或解释)将 XAML 接受为语言、并且可以生成结果基础类以供运行时对象模型使用(也是根据 XAML 规范)的任意程序。默认情况下,此类处理器要么将属性值解释为一个文本字符串,要么基于属性类型或该属性特定的类型转换器将该属性值转换为对象。不过,有时也存在要求其他行为的情况。例如,可能指示 XAML 处理器:某个属性的值应该是对已构造对象或静态对象的引用。或者指示 XAML 处理器使用向对象的构造函数提供非默认参数的语法。相对于指定的 XAML 处理器默认行为,这是一种反常行为。

基本标记扩展语法

可以实现标记扩展以便为属性 (Attribute) 用法中的属性 (Property) 和/或属性 (Property) 元素用法中的属性 (Property) 提供值。

当用于提供属性值时,将标记扩展与 XAML 处理器区分开的语法就是左右大括号({ 和 })。然后,由紧跟在左大括号后面的字符串标记来标识标记扩展的类型。

当用在属性元素语法中时,标记扩展在外观上与其他任何用于提供属性元素值的元素相同,即:一个将标记扩展类作为一个元素引用并以尖括号 (<>) 括起的 XAML 元素声明。

特定于 WPF 的标记扩展

WPF 编程中最常用的标记扩展是支持资源引用的标记扩展(StaticResource 和 DynamicResource)以及支持数据绑定的标记扩展 (Binding)。

StaticResource 通过替换已定义资源的值来为 XAML 属性提供值。有关详细信息,请参见 StaticResource 标记扩展

DynamicResource 通过将值推迟为对资源的运行时引用来为 XAML 属性提供值。动态资源引用强制在每次访问此类资源时都重新进行查找。有关详细信息,请参见 DynamicResource 标记扩展

Binding 按应用于元素的数据上下文来为属性提供数据绑定值。此标记扩展相对复杂,因为它会启用大量内联语法来指定数据绑定。有关详细信息,请参见 绑定标记扩展

RelativeSource 为可以在运行时元素树中定位若干可能关系的 Binding 提供源信息。对于在多用途模板中创建的绑定,或在未充分了解周围的元素树的情况下以代码创建的绑定,上述标记扩展会提供专用源。有关详细信息,请参见 RelativeSource MarkupExtension

通过 TemplateBinding,控件模板可以使用来自要利用该模板的类的对象模型定义属性中的模板化属性的值。有关详细信息,请参见 TemplateBinding 标记扩展。有关 TemplateBinding 的实际用途的更多信息,请参见使用 ControlTemplates 设置样式的示例

XAML 定义的标记扩展

有几个标记扩展并非是 XAML 的 WPF 应用程序所特有的,而是属于 XAML 语言规范的一部分。它们通常由语法中的 x: 前缀标识,如您在常见用法中所见到的一样。这些语言元素的 WPF 实现使用相同的 MarkupExtension 基类来提供实现。

说明:

x: 前缀在 XAML 应用程序或文档的根元素中用于 XAML 命名空间的典型 XML 命名空间映射。例如,Microsoft Visual Studio 2005 模板使用此 x: 映射启动 XAML 文件。您可以在自己的 XML 命名空间映射中选择一个不同的前缀标记,但是本文档将采用默认的 x: 映射,并通过它来标识属于 XAML 命名空间已定义部分的那些实体,这与 WPF 命名空间或其他任意 CLR 或 XML 命名空间是相反的。

x:Type 为命名类型提供 Type 对象。此标记扩展最常用于样式和模板。有关详细信息,请参见 x:Type 标记扩展

x:Static 从不直接属于属性值类型、但可以计算为该类型的值类型代码实体中生成静态值。有关详细信息,请参见 x:Static 标记扩展

x:Null 将 null 指定为 XAML 属性的值。有关详细信息,请参见 x:Null 标记扩展

在特意不使用基元素和控件模型提供的集合支持的情况下,x:Array 为 XAML 语法中常规数组的创建提供支持。有关详细信息,请参见 x:Array 标记扩展

有关标记扩展语法的更多信息

*Extension 类

每个标记扩展的行为都会通过从 MarkupExtension 派生的 *Extension 类通知给 XAML 处理器,并提供 ProvideValue 方法的实现。每个扩展的此方法都会定义在计算标记扩展后将返回哪个对象。通常,通过使用传递给标记扩展的各个字符串标记来对返回的对象进行实例化或设置。

例如,StaticResourceExtension 类提供实际资源查找的图面实现,以便其 ProvideValue 实现返回请求的对象,该特定实现的输入是用于按其 x:Key 查找资源的字符串。如果您使用的是现有标记扩展,则其中的大部分实现详细信息都无关紧要。

后续字符串标记的扩展类解释

跟在标记扩展标识符后面、并且仍在括号内的字符串标记由 XAML 处理器通过以下方式之一解释:

  • 逗号始终代表各个标记的分隔符。因此,文本逗号无法传递给标记扩展。

  • 如果各个分隔的标记不包含任何等号,则每个标记都将被视为构造函数参数。每个构造函数参数都必须按该签名所期望的类型给出,并按照该签名所期望的顺序排列。

    说明:

    XAML 处理器必须调用与对的数量这一参数计数匹配的构造函数。为此,如果您要实现自定义标记扩展,请不要提供具有相同实参计数的多个形参;对于当存在多个具有相同形参计数的标记扩展构造函数时将发生的情况,尚未定义相应的行为。

  • 如果各个分隔的标记包含等号,则 XAML 处理器会首先为标记扩展调用默认构造函数。之后,每个“名称=值”对都会被解释为标记扩展上存在的属性名称以及赋给该属性的值。

  • 如果在标记扩展中的构造函数行为与属性设置行为之间存在并行结果,则您使用哪个行为都无关紧要。如果仅仅因为将“属性=值”对用于具有多个可设置属性的标记扩展就可以令您的标记意图性更强,并减小意外转置构造函数参数的可能性(当您指定“属性=值”对时,这些属性可以为任意顺序),那么这种用法更常见。另外,无法保证标记扩展提供设置每个可设置属性的构造函数参数。例如,Binding 是一个标记扩展,具有多个可以通过“属性=值”形式的扩展来设置的属性,但 Binding 仅支持两个构造函数,即默认构造函数和一个设置初始路径的构造函数。

转义文本大括号

XAML 处理器中的属性处理使用大括号作为标记扩展的指示符。必要时,还可以使用后面跟文本大括号的空大括号对来输入转义序列,从而生成文本大括号字符属性值。请参见 {} 转义序列/标记扩展

嵌套扩展语法

支持多个标记扩展的嵌套,并且将首先计算每个标记扩展的最里层,例如:

<Setter Property="Background"

Value="{DynamicResource {x:Static SystemColors.ControlBrushKey}}" />

有关标记扩展和属性元素语法的更多信息

当用作填写属性元素值的对象元素时,标记扩展类在外观上与可用在 XAML 中的普通元素没有区别。这种情况下,普通元素与标记扩展之间的实际差异就在于标记扩展要么可计算为一个类型值,要么延迟为一个表达式,因此属性值的任何可能的类型错误的机制都将是不同的,这与后期绑定属性在其他编程模型中的处理方式类似。普通元素将计算为类型,而属性是在编译时直接设置的。

当用在对象元素语法中以填充属性元素时,大部分标记扩展都不会包含内容或任何进一步的属性元素语法,这样您就可以关闭对象元素标记,而不提供任何子元素。不论何时 XAML 处理器遇到任何对象元素,都会调用该类的构造函数以实例化从已分析元素创建的对象。标记扩展类也一样;因此,如果您希望自己的标记扩展在对象元素语法中可用,就必须提供默认构造函数。有些现有标记扩展至少具有一个必需的属性值,为了使初始化有效,必须指定该值。在这种情况下,通常会将该属性值作为对象元素的属性特性来指定。在 XAML 命名空间 (x:) 语言功能WPF 命名空间 XAML 扩展参考页中,将指出具有必需属性的标记扩展(以及必需属性的名称)。参考页还将指出特定标记扩展是否禁止使用对象元素语法或属性语法。一个值得注意的情况是 x:Array 标记扩展,它无法支持属性语法,因为必须指定该数组的内容。数组内容的处理方式与常规对象一样,因此属性没有默认类型转换器是可行的。另外,x:Array 标记扩展需要 Type 参数。

请参见

概念

XAML 概述

参考

StaticResource 标记扩展

绑定标记扩展

DynamicResource 标记扩展

x:Type 标记扩展

其他资源

XAML 命名空间 (x:) 语言功能

WPF 命名空间 XAML 扩展