XAML 语法详述

本主题定义用于描述 XAML 语法元素的术语。 在本文档的其余部分,这些术语经常专门用于 WPF 文档,以及用于使用 XAML 或是 XAML 语言支持在 System.Xaml 级别启用的基本 XAML 概念的其他框架。 本主题扩展了在 WPF 中的 XAML 主题中介绍的基本术语。

XAML 语言规范

此处定义的 XAML 语法术语也在 XAML 语言规范中进行定义或引用。 XAML 是基于 XML 的语言,遵循或扩展 XML 结构规则。 某些术语来自或基于描述 XML 语言或 XML 文档对象模型时常用的术语。

有关 XAML 语言规范的详细信息,请从 Microsoft 下载中心下载 [MS-XAML]

XAML 和 CLR

XAML 是一种标记语言。 顾名思义,公共语言运行时 (CLR) 可实现运行时执行。 XAML 本身不是 CLR 运行时直接使用的公共语言之一。 相反,可以将 XAML 视为支持其自己的类型系统。 WPF 使用的特定 XAML 分析系统基于 CLR 和 CLR 类型系统构建。 XAML 类型映射到 CLR 类型,以便在分析适用于 WPF 的 XAML 时实例化运行时表示形式。 因此,本文档中语法讨论的其余部分会包含对 CLR 类型系统的引用,尽管 XAML 语言规范中的等效语法讨论不包含这些引用。 (按照 XAML 语言规范级别,XAML 类型可以映射到任何其他类型系统,这不必是 CLR,但这需要创建和使用其他 XAML 分析器。)

类型和类继承的成员

显示为 WPF 类型的 XAML 成员的属性和事件通常是从基类型继承的。 例如,请考虑以下示例:<Button Background="Blue" .../>。 如果要查看类定义、反射结果或文档,Background 属性不是 Button 类中的立即声明属性。 相反,Background 从基类 Control 进行继承。

WPF XAML 元素的类继承行为与 XML 标记的架构强制解释有显著区别。 类继承可能变得十分复杂,特别是在中间基类是抽象类,或者涉及接口时。 这是 XAML 元素集及其允许属性难以使用通常用于 XML 编程的架构类型(如 DTD 或 XSD 格式)准确且完整地表示的原因之一。 另一个原因是 XAML 语言本身的扩展性和类型映射功能排除了允许类型和成员的任何固定表示形式的完整性。

对象元素语法

对象元素语法是 XAML 标记语法,通过声明 XML 元素来实例化 CLR 类或结构。 此语法类似于其他标记语言(如 HTML)的元素语法。 对象元素语法以左尖括号 (<) 开头,后面紧跟进行实例化的类或结构的类型名称。 零个或多个空格可以跟在类型名称后面,零个或多个属性也可以在对象元素上声明,使用一个或多个空格分隔每个属性名称=“值”对。 最后,必须满足以下条件之一:

  • 元素和标记必须以正斜杠 (/) 结尾,后面紧跟右尖括号 (>)。

  • 开始标记必须以右尖括号 (>) 结尾。 其他对象元素、属性元素或内部文本可以跟在开始标记后面。 此处可能包含的确切内容通常受元素的对象模型约束。 对象元素的等效结束标记也必须存在,与其他开始和结束标记对进行正确的嵌套和平衡。

.NET 实现的 XAML 有一组规则,这些规则将对象元素映射到类型、将特性映射到属性或事件,以及将 XAML 命名空间映射到 CLR 命名空间和程序集。 对于 WPF 和 .NET,XAML 对象元素会映射到引用程序集中定义的 .NET 类型,特性会映射到这些类型的成员。 在 XAML 中引用 CLR 类型时,还可以访问该类型的继承成员。

例如,以下示例是对象元素语法,它实例化 Button 类的新实例的,还指定 Name 特性以及该特性的值:

<Button Name="CheckoutButton"/>

以下示例是还包括 XAML 内容属性语法的对象元素语法。 其中包含的内部文本会用于设置 TextBox XAML 内容属性 Text

<TextBox>This is a Text Box</TextBox>

内容模型

类在语法方面可能支持用作 XAML 对象元素,但只有将该元素置于整体内容模型或元素树的预期位置时,它才会在应用程序或页面中正常运行。 例如,MenuItem 通常应仅作为 MenuBase 派生类(例如 Menu)的子级进行放置。 特定元素的内容模型在可用作 XAML 元素的控件和其他 WPF 类的类页面上记录为注解的一部分。

对象元素的属性

XAML 中的属性通过各种可能的语法进行设置。 根据所设置的属性的基础类型系统特征,可用于特定属性的语法会有所不同。

通过设置属性的值,可在对象存在于运行时对象图中时,向它们添加功能或特征。 从对象元素创建的对象的初始状态基于无参数构造函数行为。 通常,应用程序会使用任何给定对象的完全默认实例以外的其他内容。

特性语法(属性)

特性语法是 XAML 标记语法,它通过对现有对象元素声明特性来设置属性的值。 特性名称必须与支持相关对象元素的类的属性的 CLR 成员名称匹配。 特性名称后跟赋值运算符 (=)。 特性值必须是括在引号中的字符串。

注意

可以使用交替引号在特性中放置文本引用。 例如,可以使用单引号来声明其中包含双引号字符的字符串。 无论是使用单引号还是双引号,都应使用匹配对来开始和结束特性值字符串。 还有一些转义序列或其他方法可用于解决任何特定 XAML 语法施加的字符限制。 请参阅 XML 字符实体和 XAML

若要通过特性语法进行设置,属性必须是公共属性,并且必须可写。 后备类型系统中属性的值必须是值类型,或者必须是在访问相关后备类型时可由 XAML 处理器实例化或引用的引用类型。

对于 WPF XAML 事件,作为特性名称引用的事件必须是公共的,并且具有公共委托。

属性或事件必须是由包含对象元素实例化的类或结构的成员。

特性值的处理

左和右引号中包含的字符串值由 XAML 处理器进行处理。 对于属性,默认处理行为由基础 CLR 属性的类型确定。

特性值会按此处理顺序,使用以下内容之一进行填充:

  1. 如果 XAML 处理器遇到大括号或派生自 MarkupExtension 的对象元素,则首先计算引用的标记扩展,而不是将值作为字符串进行处理,标记扩展返回的对象会用作值。 在许多情况下,标记扩展返回的对象会是对现有对象的引用,或者是将计算延迟到运行时的表达式,不是新实例化的对象。

  2. 如果使用特性化 TypeConverter 声明属性,或者使用特性化 TypeConverter 声明该属性的值类型,则特性的字符串值会作为转换输入提交到类型转换器,转换器会返回新的对象实例。

  3. 如果没有 TypeConverter,则尝试直接转换为属性类型。 此最终级别是在 XAML 语言基元类型之间对分析器本机值进行直接转换,或者检查枚举中命名常量的名称(分析器随后会访问匹配值)。

枚举特性值

XAML 中的枚举由 XAML 分析器以内部方式进行处理,枚举的成员应通过指定枚举命名常量之一的字符串名称来指定。

对于非标志枚举值,本机行为是处理特性值的字符串并将它解析为枚举值之一。 无需如同在代码中一样,以“枚举.值”格式指定枚举。 而是仅指定值,枚举通过所设置的属性类型进行推断。 如果以“枚举.值”形式指定特性,则不会正确进行解析

对于按标志枚举,行为基于 Enum.Parse 方法。 可以通过用逗号分隔每个值,为按标志枚举指定多个值。 但是,不能合并不按标志的枚举值。 例如,不能使用逗号语法尝试创建对非标志枚举的多个条件执行操作的 Trigger

<!--This will not compile, because Visibility is not a flagwise enumeration.-->  
...  
<Trigger Property="Visibility" Value="Collapsed,Hidden">  
  <Setter ... />  
</Trigger>  
...  

支持在 XAML 中可设置的特性的按标志枚举在 WPF 中很少见。 不过,其中这样一个枚举是 StyleSimulations。 例如,可以使用逗号分隔的按标志特性语法修改 Glyphs 类的注解中提供的示例;StyleSimulations = "BoldSimulation" 可能变为 StyleSimulations = "BoldSimulation,ItalicSimulation"KeyBinding.Modifiers 是可以在其中指定多个枚举值的另一个属性。 但是,此属性恰好是特殊情况,因为 ModifierKeys 枚举支持其自己的类型转换器。 修饰符的类型转换器使用加号 (+) 作为分隔符,而不是逗号 (,)。 此转换支持更传统的语法,以便在 Microsoft Windows 编程中表示组合键,例如“Ctrl+Alt”。

属性和事件成员名称引用

指定属性时,可以引用以针对包含对象元素实例化的 CLR 类型的成员形式而存在的任何属性或事件。

或者,可以引用独立于包含对象元素的附加属性或附加事件。 (附加属性会在后面的部分中进行讨论。)

还可以使用 typeName.event 部分限定名称对可通过默认命名空间访问的任何对象中的任何事件进行命名;此语法支持为路由事件附加处理程序,其中处理程序旨在处理从子元素路由的事件,但父元素在其成员表中也不包含该事件。 此语法类似于附加事件语法,但此处的事件不是真正的附加事件。 而是使用限定名称引用事件。 有关详细信息,请参阅路由事件概述

对于某些情形,属性名称有时作为特性的值提供,而不是特性名称。 该属性名称也可以包含限定符,如采用 ownerType.dependencyPropertyName 形式指定的属性。 在 XAML 中编写样式或模板时,这种情形很常见。 作为特性值提供的属性名称的处理规则有所不同,受进行设置的属性的类型或特定 WPF 子系统的行为所控制。 有关详细信息,请参阅样式设置和模板化

属性名称的另一种用法是当特性值描述属性-属性关系时。 此功能用于数据绑定和情节提要目标,通过 PropertyPath 类及其类型转换器来实现。 有关查找语义的更完整说明,请参阅 PropertyPath XAML 语法

属性元素语法

属性元素语法是一种与元素的基本 XML 语法规则有一些差异的语法。 在 XML 中,特性的值是事实上的字符串,唯一可能的变化是所使用的字符串编码格式。 在 XAML 中,可以分配其他对象元素作为属性的值。 属性元素语法在默认情况下会启用此功能。 属性不是在元素标记中指定为特性,而是采用 elementTypeName.propertyName 形式,使用开始元素标记进行指定,在其中指定属性的值,然后结束属性元素

具体而言,语法以左尖括号 (<) 开头,后面紧跟属性元素语法包含在其中的类或结构的类型名称。 紧接着是单个点 (.),然后是属性的名称,再然后是右尖括号 (>)。 与特性语法一样,该属性必须存在于指定类型的已声明公共成员中。 要分配给属性的值包含在属性元素中。 通常,值作为一个或多个对象元素提供,因为将对象指定为值是属性元素语法旨在解决的情形。 最后,必须提供指定同一个 elementTypeName.propertyName 组合的等效结束标记,与其他元素标记进行正确的嵌套和平衡

例如,下面是 ButtonContextMenu 属性的属性元素语法。

<Button>
  <Button.ContextMenu>
    <ContextMenu>
      <MenuItem Header="1">First item</MenuItem>
      <MenuItem Header="2">Second item</MenuItem>
    </ContextMenu>
  </Button.ContextMenu>
  Right-click me!</Button>

如果指定的属性类型是基元值类型(如 String),或是在其中指定了名称的枚举,属性元素中的值也可以作为内部文本提供。 这两种用法有些不常见,因为每种情况也可以使用更简单的特性语法。 使用字符串填充属性元素的一种情形是用于不是 XAML 内容属性,但仍用于 UI 文本表示形式的属性,特定空白元素(如换行符)需要出现在该 UI 文本中。 特性语法不能保留换行符,但属性元素语法可以,只要有效空白保留处于活动状态(有关详细信息,请参阅 XAML 中的空白处理)。 另一种情形是可以将 x:Uid 指令应用于属性元素,从而将其中的值标记为应在 WPF 输出 BAML 中或通过其他技术本地化的值。

WPF 逻辑树中未表示属性元素。 属性元素只是用于设置属性的特定语法,不是具有支持它的实例或对象的元素。 (有关逻辑树概念的详细信息,请参阅 WPF 中的树。)

对于支持特性和属性元素语法的属性,这两种语法通常具有相同的结果,不过细微之处(如空白处理)可能在语法之间略有不同。

集合语法

XAML 规范要求 XAML 处理器实现标识值类型为集合的属性。 .NET 中的常规 XAML 处理器实现基于托管代码和 CLR,它通过下列方法之一标识集合类型:

如果属性的类型是集合,则推断的集合类型不需要在标记中指定为对象元素。 相反,旨在成为集合中的项的元素被指定为属性元素的一个或多个子元素。 每个此类项会在加载期间计算为对象,并通过调用隐式集合的 Add 方法来添加到集合中。 例如,StyleTriggers 属性采用实现 IList 的专用集合类型 TriggerCollection。 不需要实例化标记中的 TriggerCollection 对象元素。 而是将一个或多个 Trigger 项指定为 Style.Triggers 属性元素中的元素,其中 Trigger(或派生类)是应作为强类型化的隐式 TriggerCollection 的项类型的类型。

<Style x:Key="SpecialButton" TargetType="{x:Type Button}">
  <Style.Triggers>
    <Trigger Property="Button.IsMouseOver" Value="true">
      <Setter Property = "Background" Value="Red"/>
    </Trigger>
    <Trigger Property="Button.IsPressed" Value="true">
      <Setter Property = "Foreground" Value="Green"/>
    </Trigger>
  </Style.Triggers>
</Style>

属性可以是集合类型以及该类型和派生类型和 XAML 内容属性,本主题下一节对此进行了讨论。

隐式集合元素会在逻辑树表示形式中创建成员,即使它不会作为元素出现在标记中。 通常,父类型的构造函数对作为其属性之一的集合执行实例化,而最初为空的集合会成为对象树的一部分。

注意

集合检测不支持泛型列表和字典接口(IList<T>IDictionary<TKey,TValue>)。 但是,可将 List<T> 类用作基类,因为它直接实现 IList;或将 Dictionary<TKey,TValue> 用作基类,因为它直接实现 IDictionary

在集合类型的 .NET 参考页中,这种故意对集合省略对象元素的语法有时会在 XAML 语法部分中注明为隐式集合语法。

除了根元素之外,XAML 文件中作为另一个元素的子元素嵌套的每个对象元素实际上是以下一种或两种情况的元素:其父元素的隐式集合属性的成员,或者为父元素指定 XAML 内容属性值的元素(XAML 内容属性会在后面的部分中进行讨论)。 换句话说,标记页中的父元素和子元素的关系实际上是根处的单个对象,并且根下的每个对象元素都是提供父级的属性值的单个实例,或者是集合中也是父级的集合类型属性值的一个项。 此单根概念与 XML 相同,在加载 XAML 的 API(如 Load)行为中经常得到加强。

以下示例是一种语法,其中具有显式指定的集合 (GradientStopCollection) 的对象元素。

<LinearGradientBrush>  
  <LinearGradientBrush.GradientStops>  
    <GradientStopCollection>  
      <GradientStop Offset="0.0" Color="Red" />  
      <GradientStop Offset="1.0" Color="Blue" />  
    </GradientStopCollection>  
  </LinearGradientBrush.GradientStops>  
</LinearGradientBrush>  

请注意,并不总是可以显式声明集合。 例如,尝试在前面所示的 Triggers 示例中显式声明 TriggerCollection 会失败。 显式声明集合要求集合类必须支持无参数构造函数,而 TriggerCollection 没有无参数构造函数。

XAML 内容属性

XAML 内容语法是一种仅在指定 ContentPropertyAttribute 作为类声明一部分的类上启用的语法。 ContentPropertyAttribute 会引用作为该类型元素(包括派生类)的内容属性的属性名称。 由 XAML 处理器进行处理时,在对象元素的开始标记与结束标记之间找到的任何子元素或内部文本都会分配给该对象的 XAML 内容属性值。 允许为内容属性指定显式属性元素,但此用法通常不会出现在 .NET 参考的 XAML 语法部分中。 显式/详细技术偶尔对使标记清晰或是在标记样式方面有价值,但内容属性的意图通常是简化标记,以便可以直接嵌套直观上以父子形式相关的元素。 按照严格的 XAML 语言定义,元素上其他属性的属性元素标记不会分配为“内容”;它们以前按 XAML 分析器的处理顺序进行处理,不被视为“内容”。

XAML 内容属性值必须是连续的

XAML 内容属性的值必须完全在该对象元素的其他任何属性元素之前或之后指定。 无论 XAML 内容属性的值是指定为字符串还是一个或多个对象,情况都是如此。 例如,以下标记不会进行分析:

<Button>I am a
  <Button.Background>Blue</Button.Background>  
  blue button</Button>  

这实质上是非法的,因为如果是使用内容属性的属性元素语法将此语法设为显式,则内容属性会设置两次:

<Button>  
  <Button.Content>I am a </Button.Content>  
  <Button.Background>Blue</Button.Background>  
  <Button.Content> blue button</Button.Content>  
</Button>  

一个类似的非法示例是,如果内容属性是集合,子元素与属性元素交织在一起:

<StackPanel>  
  <Button>This example</Button>  
  <StackPanel.Resources>  
    <SolidColorBrush x:Key="BlueBrush" Color="Blue"/>  
  </StackPanel.Resources>  
  <Button>... is illegal XAML</Button>  
</StackPanel>  

内容属性和集合语法组合

若要接受多个对象元素作为内容,内容属性的类型必须明确为集合类型。 与集合类型的属性元素语法类似,XAML 处理器必须标识属于集合类型的类型。 如果元素具有 XAML 内容属性,并且 XAML 内容属性的类型是集合,则隐式集合类型不需要在标记中指定为对象元素,并且 XAML 内容属性不需要指定为属性元素。 因此,标记中的明显内容模型现在可以将多个子元素分配为内容。 下面是 Panel 派生类的内容语法。 所有 Panel 派生类都会建立 XAML 内容属性以作为 Children,这需要 UIElementCollection 类型的值。

<Page
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  >
  <StackPanel>
    <Button>Button 1</Button>
    <Button>Button 2</Button>
    <Button>Button 3</Button>
  </StackPanel>
</Page>

请注意,标记中既不需要 Children 的属性元素,也不需要 UIElementCollection 的元素。 这是 XAML 的设计功能,以便递归包含的定义 UI 的元素可更直观地表示为具有直接父子元素关系的嵌套元素树,而无需插入属性元素标记或集合对象。 事实上根据设计,UIElementCollection 不能在标记中显式指定为对象元素。 因为它的唯一预期用途是作为隐式集合,UIElementCollection 不会公开公共无参数构造函数,因而无法实例化为对象元素。

将对象中的属性元素和对象元素与内容属性混合

XAML 规范声明,XAML 处理器可以强制用于填充对象元素内 XAML 内容属性的对象元素必须是连续的,不得混合。 WPF XAML 处理器会强制实施这一针对混合属性元素和内容的限制。

可以将子对象元素作为对象元素中的第一个直接标记。 随后可以引入属性元素。 或者,可以指定一个或多个属性元素,随后指定内容,再指定更多属性元素。 但是,一旦属性元素跟在内容后面,便不能引入任何进一步的内容,只能添加属性元素。

此内容/属性元素顺序要求不适用于用作内容的内部文本。 但是,使内部文本保持连续仍然是一种很好的标记样式,因为如果属性元素与内部文本交织在一起,则难以在标记中直观地检测到有效空白。

XAML 命名空间

前面的语法示例都未指定默认 XAML 命名空间以外的 XAML 命名空间。 在典型 WPF 应用程序中,默认 XAML 命名空间指定为 WPF 命名空间。 可以指定默认 XAML 命名空间以外的 XAML 命名空间,不过仍使用类似的语法。 但是,只要命名了在默认 XAML 命名空间中不可访问的类,则该类名之前必须有映射到对应 CLR 命名空间的 XAML 命名空间的前缀。 例如,<custom:Example/> 是用于实例化 Example 类的实例的对象元素语法,其中包含该类(并且可能有包含后备类型的外部程序集信息)的 CLR 命名空间以前映射到 custom 前缀。

有关 XAML 命名空间的详细信息,请参阅 WPF XAML 的 XAML 命名空间和命名空间映射

标记扩展

XAML 定义了一个标记扩展编程实体,该实体可实现跳过字符串特性值或对象元素的正常 XAML 处理器处理,将处理延迟到后备类。 在使用特性语法时向 XAML 处理器标识标记扩展的字符是左大括号 ({),后跟右大括号 (}) 以外的任何字符。 左大括号后面的第一个字符串必须引用提供特定扩展行为的类,其中的引用可能会在子字符串“Extension”是真实类名的一部分时省略该子字符串。 此后可能会出现单个空格,随后扩展实现会将每个后续字符用作输入,直到遇到右大括号为止。

.NET XAML 实现使用 MarkupExtension 抽象类作为 WPF 以及其他框架或技术支持的所有标记扩展的基础。 WPF 专门实现的标记扩展通常旨在提供一种方法来引用其他现有对象,或是对将在运行时计算的对象进行延迟引用。 例如,通过指定 {Binding} 标记扩展来代替特定属性通常采用的值,可完成简单的 WPF 数据绑定。 许多 WPF 标记扩展为本来无法使用特性语法的属性实现了特性语法。 例如,Style 对象是一种相对复杂的类型,其中包含一系列嵌套的对象和属性。 WPF 中的样式通常定义为 ResourceDictionary 中的资源,然后通过请求资源的两个 WPF 标记扩展之一进行引用。 标记扩展将属性值的计算延迟到资源查找,并且可以在特性语法中提供 Style 属性的值(采用类型 Style),如以下示例所示:

<Button Style="{StaticResource MyStyle}">My button</Button>

此处,StaticResource 标识提供标记扩展实现的 StaticResourceExtension 类。 下一个字符串 MyStyle 用作非默认 StaticResourceExtension 构造函数的输入,其中从扩展字符串获取的参数会声明所请求的 ResourceKeyMyStyle 应为定义为资源的 Stylex:Key 值。 StaticResource 标记扩展用法请求在加载时通过静态资源查找逻辑使用资源提供 Style 属性值。

有关标记扩展的详细信息,请参阅标记扩展和 WPF XAML。 有关在常规 .NET XAML 实现中启用的标记扩展和其他 XAML 编程功能的参考,请参阅 XAML 命名空间 (x:) 语言功能。 有关特定于 WPF 的标记扩展,请参阅 WPF XAML 扩展

附加属性

附加属性是在 XAML 中引入的一个编程概念,通过该概念,属性可以由特定类型拥有和定义,但设置为任何元素上的特性或属性元素。 附加属性的主要用途是使标记结构中的子元素可以向父元素报告信息,而不需要跨所有元素进行广泛共享的对象模型。 反之,父元素可以使用附加属性向子元素报告信息。 有关附加属性的用途以及如何创建自己的附加属性的详细信息,请参阅附加属性概述

附加属性使用的语法表面上类似于属性元素语法,因为你也会指定 typeName.propertyName 组合。 有两个重要的差异:

  • 即使通过特性语法设置附加属性时,也可以使用 typeName.propertyName 组合。 附加属性是特性语法中唯一要求限定属性名称的情况。

  • 还可以对附加属性使用属性元素语法。 但是,对于典型属性元素语法,指定的 typeName 是包含属性元素的对象元素。 如果引用附加属性,则 typeName 是定义附加属性的类,而不是包含对象元素

附加事件

附加事件是 XAML 中引入的另一个编程概念,其中事件可由特定类型定义,但处理程序可以附加到任何对象元素上。 在 WOF 实现中,定义附加事件的类型通常是定义服务的静态类型,有时这些附加事件在公开服务的类型中通过路由事件别名公开。 附加事件的处理程序通过特性语法进行指定。 与附加事件一样,特性语法针对附加事件进行了扩展以允许使用 typeName.eventName,其中 typeName 是为附加事件基础结构提供 AddRemove 事件处理程序访问器的类,而 eventName 是事件名称。

XAML 根元素剖析

下表显示一个经过细分的典型 XAML 根元素,其中显示了根元素的特定特性:

Attribute 说明
<Page 根元素的开始对象元素
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 默认 (WPF) XAML 命名空间
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" XAML 语言 XAML 命名空间
x:Class="ExampleNamespace.ExampleCode" 将标记连接到为分部类定义的任何代码隐藏的分部类声明
> 根的对象元素结尾。 对象未结束,因为元素包含子元素

可选的非推荐 XAML 用法

以下各节介绍 XAML 处理器在技术上支持的 XAML 用法,但这些用法会产生冗长或其他美学问题,在开发包含 XAML 源的应用程序时会影响 XAML 文件保持可读性。

可选属性元素用法

可选属性元素用法包括显式写出 XAML 处理器视为隐式的元素内容属性。 例如,当你声明 Menu 的内容时,可以选择将 MenuItems 集合显式声明为 <Menu.Items> 属性元素标记,并将每个 MenuItem 放置在 <Menu.Items> 中,而不是使用隐式 XAML 处理器行为(Menu 中的所有子元素都必须是 MenuItem 并且放置在 Items 集合中)。 有时,可选用法可帮助直观地阐明标记中表示的对象结构。 或者,有时显式属性元素用法可以避免在技术上可正常运行但视觉上令人困惑的标记,例如特性值中的嵌套标记扩展。

完整 typeName.memberName 限定属性

特性的 typeName.memberName 形式实际上比路由事件情况更普遍。 但在其他情况下,该形式是多余的,你应避免使用它(如果只是出于标记样式和可读性的原因)。 在以下示例中,对 Background 特性的所有三个引用都完全等效:

<Button Background="Blue">Background</Button>
<Button Button.Background="Blue">Button.Background</Button>
<Button Control.Background="Blue">Control.Background</Button>

Button.Background 可正常工作,因为 Button 上对该属性的限定查找成功(Background 继承自 Control),并且 Button 是对象元素的类或基类。 Control.Background 可正常工作,因为 Control 类实际定义 Background并且 ControlButton 基类。

但是,以下 typeName.memberName 形式示例不起作用,因而显示为已注释掉

<!--<Button Label.Background="Blue">Does not work</Button> -->

LabelControl 的另一个派生类,如果在 Label 对象元素中指定了 Label.Background,则此用法将正常工作。 但是,由于 Label 不是 Button 的类或基类,因此指定 XAML 处理器行为是随后将 Label.Background 作为附加属性进行处理。 Label.Background 不是可用的附加属性,此用法会失败。

baseTypeName.memberName 属性元素

与 typeName.memberName 形式适用于特性语法的方式类似,baseTypeName.memberName 语法适用于属性元素语法。 例如,以下语法可正常工作:

<Button>Control.Background PE
  <Control.Background>
    <LinearGradientBrush StartPoint="0,0" EndPoint="1,1">
      <GradientStop Color="Yellow" Offset="0.0" />
      <GradientStop Color="LimeGreen" Offset="1.0" />
    </LinearGradientBrush>
    </Control.Background>
</Button>

此处,属性元素作为 Control.Background 提供,即使属性元素包含在 Button 中。

但是正如 typeName.memberName 形式对于特性一样,baseTypeName.memberName 是标记中的糟糕样式,应避免使用

另请参阅