XAML 语法详述XAML Syntax In Detail

本主题定义用于描述 XAML 语法元素的术语。This topic defines the terms that are used to describe the elements of XAML syntax. 在本文档的其余部分中经常使用这些术语,这两个术语分别适用于 WPF 文档,适用于使用 XAML 的其他框架或由 system.exception 级别的 XAML 语言支持启用的基本 XAML 概念。These terms are used frequently throughout the remainder of this documentation, both for WPF documentation specifically and for the other frameworks that use XAML or the basic XAML concepts enabled by the XAML language support at the System.Xaml level. 本主题概述了在主题XAML 概述(WPF)中引入的基本术语。This topic expands on the basic terminology introduced in the topic XAML Overview (WPF).

XAML 语言规范The XAML Language Specification

此处定义的 XAML 语法术语也是在 XAML 语言规范中定义或引用的。The XAML syntax terminology defined here is also defined or referenced within the XAML language specification. XAML 是一种基于 XML 的语言,并在 XML 结构规则后跟随或展开。XAML is a language based on XML and follows or expands upon XML structural rules. 其中一些术语是从或中共享的,它基于在描述 XML 语言或 XML 文档对象模型时常用的术语。Some of the terminology is shared from or is based on the terminology commonly used when describing the XML language or the XML document object model.

有关 XAML 语言规范的详细信息,请从 Microsoft 下载中心下载[MS-XAML]For more information about the XAML language specification, download [MS-XAML] from the Microsoft Download Center.

XAML 和 CLRXAML and CLR

XAML 是一种标记语言。XAML is a markup language. 公共语言运行时(CLR)根据其名称的隐含,启用运行时执行。The common language runtime (CLR), as implied by its name, enables runtime execution. XAML 本身不是 CLR 运行时直接使用的公共语言之一。XAML is not by itself one of the common languages that is directly consumed by the CLR runtime. 相反,可以将 XAML 视为支持其自己的类型系统。Instead, you can think of XAML as supporting its own type system. WPF 使用的特定 XAML 分析系统是在 CLR 和 CLR 类型系统上构建的。The particular XAML parsing system that is used by WPF is built on the CLR and the CLR type system. 在分析用于 WPF 的 XAML 时,XAML 类型会映射到 CLR 类型以实例化运行时表示形式。XAML types are mapped to CLR types to instantiate a run time representation when the XAML for WPF is parsed. 出于此原因,本文档中的语法讨论的其余部分将包括对 CLR 类型系统的引用,尽管 XAML 语言规范中的等效语法讨论不包括在内。For this reason, the remainder of discussion of syntax in this document will include references to the CLR type system, even though the equivalent syntax discussions in the XAML language specification do not. (根据 XAML 语言规范级别,XAML 类型可以映射到任何其他类型系统,而无需是 CLR,但这需要创建和使用不同的 XAML 分析器。)(Per the XAML language specification level, XAML types could be mapped to any other type system, which does not have to be the CLR, but that would require the creation and use of a different XAML parser.)

类型和类继承的成员Members of Types and Class Inheritance

作为 WPFWPF 类型的 XAML 成员出现的属性和事件通常继承自基类型。Properties and events as they appear as XAML members of a WPFWPF type are often inherited from base types. 例如,请看下面的示例: <Button Background="Blue" .../>For example, consider this example: <Button Background="Blue" .../>. 如果要查看类定义、反射结果或文档,则 Background 属性不是 Button 类上的直接声明的属性。The Background property is not an immediately declared property on the Button class, if you were to look at the class definition, reflection results, or the documentation. 相反,Background 是从基 Control 类继承的。Instead, Background is inherited from the base Control class.

WPFWPF XAML 元素的类继承行为是对 XML 标记的架构强制解释的重大影响。The class inheritance behavior of WPFWPF XAML elements is a significant departure from a schema-enforced interpretation of XML markup. 类继承可能会变得复杂,尤其是在中间基类是抽象类或涉及接口时。Class inheritance can become complex, particularly when intermediate base classes are abstract, or when interfaces are involved. 这是一种原因,这是一组 XAML 元素及其允许的特性很难准确准确地使用通常用于 XML 编程(如 DTD 或 XSD 格式)的架构类型来表示。This is one reason that the set of XAML elements and their permissible attributes is difficult to represent accurately and completely using the schema types that are typically used for XML programming, such as DTD or XSD format. 另一个原因是 XAML 语言自身的可扩展性和类型映射功能排除了允许的类型和成员的任何固定表示形式的完整性。Another reason is that extensibility and type-mapping features of the XAML language itself preclude completeness of any fixed representation of the permissible types and members.

对象元素语法Object Element Syntax

对象元素语法是通过声明 XML 元素来实例化 CLR 类或结构的 XAML 标记语法。Object element syntax is the XAML markup syntax that instantiates a CLR class or structure by declaring an XML element. 此语法类似于其他标记语言(如 HTML)的元素语法。This syntax resembles the element syntax of other markup languages such as HTML. 对象元素语法以左尖括号(<)开头,后跟要实例化的类或结构的类型名称。Object element syntax begins with a left angle bracket (<), followed immediately by the type name of the class or structure being instantiated. 零个或多个空格可以跟在类型名称之后,还可以在 object 元素上声明零个或多个属性,并在每个属性名称 = "value" 对之间用一个或多个空格分隔。Zero or more spaces can follow the type name, and zero or more attributes may also be declared on the object element, with one or more spaces separating each attribute name="value" pair. 最后,必须满足以下条件之一:Finally, one of the following must be true:

  • 元素和标记必须以正斜杠(/)结束,后面紧跟右尖括号(>)。The element and tag must be closed by a forward slash (/) followed immediately by a right angle bracket (>).

  • 开始标记必须由右尖括号(>)完成。The opening tag must be completed by a right angle bracket (>). 其他对象元素、属性元素或内部文本可以跟随开始标记。Other object elements, property elements, or inner text, can follow the opening tag. 此处可以确切包含的内容通常受元素的对象模型的约束。Exactly what content may be contained here is typically constrained by the object model of the element. 还必须存在对象元素的等效结束标记,并将其与其他开始和结束标记对进行适当的嵌套和平衡。The equivalent closing tag for the object element must also exist, in proper nesting and balance with other opening and closing tag pairs.

.NET 实现的 XAML 包含一组规则,这些规则将对象元素映射到类型、属性或事件中的属性,以及 XAML 命名空间到 CLR 命名空间和程序集。XAML as implemented by .NET has a set of rules that map object elements into types, attributes into properties or events, and XAML namespaces to CLR namespaces plus assembly. 对于 WPF 和 .NET,XAML 对象元素映射到在引用的程序集中定义的 .NET 类型,属性映射到这些类型的成员。For WPF and .NET, XAML object elements map to .NET types as defined in referenced assemblies, and the attributes map to members of those types. 在 XAML 中引用 CLR 类型时,还可以访问该类型的继承成员。When you reference a CLR type in XAML, you have access to the inherited members of that type as well.

例如,下面的示例是用于实例化 Button 类的新实例的对象元素语法,还指定了 Name 属性和该属性的值:For example, the following example is object element syntax that instantiates a new instance of the Button class, and also specifies a Name attribute and a value for that attribute:

<Button Name="CheckoutButton"/>

下面的示例是包含 XAML 内容属性语法的对象元素语法。The following example is object element syntax that also includes XAML content property syntax. 中包含的内部文本将用于设置 TextBox XAML 内容属性,TextThe inner text contained within will be used to set the TextBox XAML content property, Text.

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

内容模型Content Models

类在语法方面可能支持使用作为 XAML 对象元素,但当该元素置于整体内容模型或元素树的预期位置时,它将仅在应用程序或页中正常运行。A class might support a usage as a XAML object element in terms of the syntax, but that element will only function properly in an application or page when it is placed in an expected position of an overall content model or element tree. 例如,MenuItem 通常只应作为 MenuBase 派生类(如 Menu)的子级。For example, a MenuItem should typically only be placed as a child of a MenuBase derived class such as Menu. 特定元素的内容模型记录为控件的类页和其他 WPFWPF 类的注释的一部分,这些类可用作 XAML 元素。Content models for specific elements are documented as part of the remarks on the class pages for controls and other WPFWPF classes that can be used as XAML elements.

对象元素的属性Properties of Object Elements

XAML 中的属性由各种可能的语法设置。Properties in XAML are set by a variety of possible syntaxes. 根据要设置的属性的基础类型系统特征,可用于特定属性的语法将有所不同。Which syntax can be used for a particular property will vary, based on the underlying type system characteristics of the property that you are setting.

通过设置属性的值,您可以将功能或特征添加到对象中,因为它们存在于运行时对象关系图中。By setting values of properties, you add features or characteristics to objects as they exist in the run time object graph. 对象元素中创建的对象的初始状态基于无参数构造函数的行为。The initial state of the created object from a object element is based on the parameterless constructor behavior. 通常,应用程序将使用任何给定对象的完全默认实例以外的内容。Typically, your application will use something other than a completely default instance of any given object.

特性语法(属性)Attribute Syntax (Properties)

特性语法是 XAML 标记语法,它通过在现有对象元素上声明特性来设置属性的值。Attribute syntax is the XAML markup syntax that sets a value for a property by declaring an attribute on an existing object element. 特性名称必须与支持相关对象元素的类的属性的 CLR 成员名称匹配。The attribute name must match the CLR member name of the property of the class that backs the relevant object element. 特性名称后跟赋值运算符(=)。The attribute name is followed by an assignment operator (=). 属性值必须是括在引号内的字符串。The attribute value must be a string enclosed within quotes.

备注

可以使用交替引号将文本引号置于特性中。You can use alternating quotes to place a literal quotation mark within an attribute. 例如,可以将单引号用作一种声明其中包含双引号字符的字符串。For instance you can use single quotes as a means to declare a string that contains a double quote character within it. 无论使用单引号还是双引号,都应使用匹配对来打开和关闭属性值字符串。Whether you use single or double quotes, you should use a matching pair for opening and closing the attribute value string. 还提供了一些转义序列或其他技术,可用于解决任何特定 XAML 语法施加的字符限制。There are also escape sequences or other techniques available for working around character restrictions imposed by any particular XAML syntax. 请参阅XML 字符实体和 XAMLSee XML Character Entities and XAML.

为了通过属性语法进行设置,属性必须是公共的,并且必须是可写的。In order to be set through attribute syntax, a property must be public and must be writeable. 后备类型系统中的属性的值必须是值类型,或者必须是 XAML 处理器在访问相关支持类型时可以实例化或引用的引用类型。The value of the property in the backing type system must be a value type, or must be a reference type that can be instantiated or referenced by a XAML processor when accessing the relevant backing type.

对于 WPF XAML 事件,作为特性名称引用的事件必须是公共的,并且必须具有公共委托。For WPF XAML events, the event that is referenced as the attribute name must be public and have a public delegate.

属性或事件必须是由包含对象元素实例化的类或结构的成员。The property or event must be a member of the class or structure that is instantiated by the containing object element.

属性值的处理Processing of Attribute Values

由 XAML 处理器处理的左引号和右引号内包含的字符串值。The string value contained within the opening and closing quotation marks is processed by a XAML processor. 对于属性,默认处理行为由基础 CLR 属性的类型确定。For properties, the default processing behavior is determined by the type of the underlying CLR property.

使用此处理顺序通过以下方式之一填充属性值:The attribute value is filled by one of the following, using this processing order:

  1. 如果 XAML 处理器遇到大括号,或派生自 MarkupExtension的对象元素,则首先计算引用的标记扩展,而不是将值作为字符串进行处理,而由标记扩展返回的对象将用作值。If the XAML processor encounters a curly brace, or an object element that derives from MarkupExtension, then the referenced markup extension is evaluated first rather than processing the value as a string, and the object returned by the markup extension is used as the value. 在许多情况下,由标记扩展返回的对象将是对现有对象的引用,或将计算延迟到运行时的表达式,而不是新实例化的对象。In many cases the object returned by a markup extension will be a reference to an existing object, or an expression that defers evaluation until run time, and is not a newly instantiated object.

  2. 如果该属性是使用特性化的 TypeConverter声明的,或者该属性的值类型是使用特性化的 TypeConverter进行声明的,则该特性的字符串值将作为转换输入提交给类型转换器,转换器将返回一个新的对象实例.If the property is declared with an attributed TypeConverter, or the value type of that property is declared with an attributed TypeConverter, the string value of the attribute is submitted to the type converter as a conversion input, and the converter will return a new object instance.

  3. 如果没有 TypeConverter,则尝试直接转换为属性类型。If there is no TypeConverter, a direct conversion to the property type is attempted. 此最终级别是 XAML 语言基元类型之间的分析器本机值的直接转换,或者是对枚举中的命名常量名称的检查(分析器然后访问匹配的值)。This final level is a direct conversion at the parser-native value between XAML language primitive types, or a check for the names of named constants in an enumeration (the parser then accesses the matching values).

枚举属性值Enumeration Attribute Values

XAML 中的枚举在本质上由 XAML 分析器进行处理,并且应通过指定枚举命名常量之一的字符串名称来指定枚举的成员。Enumerations in XAML are processed intrinsically by XAML parsers, and the members of an enumeration should be specified by specifying the string name of one of the enumeration's named constants.

对于 nonflag 枚举值,本机行为是处理属性值的字符串,并将其解析为枚举值之一。For nonflag enumeration values, the native behavior is to process the string of an attribute value and resolve it to one of the enumeration values. 不在格式枚举中指定枚举。,这与在代码中执行的操作相同。You do not specify the enumeration in the format Enumeration.Value, as you do in code. 相反,您只需指定枚举将由您设置的属性的类型推断。Instead, you specify only Value, and Enumeration is inferred by the type of the property you are setting. 如果在枚举中指定属性,则为。格式,它将无法正确解析。If you specify an attribute in the Enumeration.Value form, it will not resolve correctly.

对于 flagwise 枚举,行为基于 Enum.Parse 方法。For flagwise enumerations, the behavior is based on the Enum.Parse method. 可以通过用逗号分隔每个值来指定 flagwise 枚举的多个值。You can specify multiple values for a flagwise enumeration by separating each value with a comma. 但是,不能合并不 flagwise 的枚举值。However, you cannot combine enumeration values that are not flagwise. 例如,不能使用逗号语法来尝试创建对 nonflag 枚举的多个条件执行操作的 TriggerFor instance, you cannot use the comma syntax to attempt to create a Trigger that acts on multiple conditions of a nonflag enumeration:

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

在 WPF 中,支持在 XAML 中设置的属性的 Flagwise 枚举非常罕见。Flagwise enumerations that support attributes that are settable in XAML are rare in WPF. StyleSimulations一个这样的枚举。However, one such enumeration is StyleSimulations. 例如,可以使用逗号分隔的 flagwise 特性语法来修改 Glyphs 类的 "备注" 中提供的示例;StyleSimulations = "BoldSimulation" 可能会 StyleSimulations = "BoldSimulation,ItalicSimulation"You could, for instance, use the comma-delimited flagwise attribute syntax to modify the example provided in the Remarks for the Glyphs class; StyleSimulations = "BoldSimulation" could become StyleSimulations = "BoldSimulation,ItalicSimulation". KeyBinding.Modifiers 是可指定多个枚举值的另一个属性。KeyBinding.Modifiers is another property where more than one enumeration value can be specified. 但是,此属性恰好是一种特殊情况,因为 ModifierKeys 枚举支持其自己的类型转换器。However, this property happens to be a special case, because the ModifierKeys enumeration supports its own type converter. 修饰符的类型转换器使用加号(+)作为分隔符,而不是逗号(,)。The type converter for modifiers uses a plus sign (+) as a delimiter rather than a comma (,). 此转换支持更传统的语法来表示 Microsoft Windows 编程中的组合键,如 "Ctrl + Alt"。This conversion supports the more traditional syntax to represent key combinations in Microsoft Windows programming, such as "Ctrl+Alt".

属性和事件成员名称引用Properties and Event Member Name References

指定特性时,可以引用作为为包含对象元素实例化的 CLR 类型的成员存在的任何属性或事件。When specifying an attribute, you can reference any property or event that exists as a member of the CLR type you instantiated for the containing object element.

或者,可以引用附加的属性或附加事件,而不依赖于包含对象元素。Or, you can reference an attached property or attached event, independent of the containing object element. (后面的部分将讨论附加属性。)(Attached properties are discussed in an upcoming section.)

你还可以使用typeName来命名可通过默认命名空间访问的任何对象中的任何事件。事件部分限定名称;此语法支持为路由事件附加处理程序,其中处理程序旨在处理来自子元素的事件路由,但父元素的成员表中也不包含该事件。You can also name any event from any object that is accessible through the default namespace by using a typeName.event partially qualified name; this syntax supports attaching handlers for routed events where the handler is intended to handle events routing from child elements, but the parent element does not also have that event in its members table. 此语法与附加事件语法类似,但此处的事件不是真正的附加事件。This syntax resembles an attached event syntax, but the event here is not a true attached event. 而是引用具有限定名称的事件。Instead, you are referencing an event with a qualified name. 有关详细信息,请参阅路由事件概述For more information, see Routed Events Overview.

在某些情况下,属性名称有时提供为属性的值,而不是属性名称。For some scenarios, property names are sometimes provided as the value of an attribute, rather than the attribute name. 该属性名称还可以包括限定符,如以 "所有者" 格式指定的属性。dependencyPropertyNameThat property name can also include qualifiers, such as the property specified in the form ownerType.dependencyPropertyName. 在 XAML 中编写样式或模板时,这种情况很常见。This scenario is common when writing styles or templates in XAML. 作为属性值提供的属性名称的处理规则是不同的,由所设置的属性类型或特定 WPF 子系统的行为来控制。The processing rules for property names provided as an attribute value are different, and are governed by the type of the property being set or by the behaviors of particular WPF subsystems. 有关详细信息,请参阅样式设置和模板化For details, see Styling and Templating.

属性名称的另一个用法是在属性值描述属性关系时使用。Another usage for property names is when an attribute value describes a property-property relationship. 此功能用于数据绑定和情节提要目标,并由 PropertyPath 类及其类型转换器启用。This feature is used for data binding and for storyboard targets, and is enabled by the PropertyPath class and its type converter. 有关查找语义的更完整说明,请参阅PROPERTYPATH XAML 语法For a more complete description of the lookup semantics, see PropertyPath XAML Syntax.

属性元素语法Property Element Syntax

Property 元素语法是一种语法,它与元素的基本 XML 语法规则有点与其分离。Property element syntax is a syntax that diverges somewhat from the basic XML syntax rules for elements. 在 XML 中,属性的值是一个事实字符串,唯一可能的变体是使用哪种字符串编码格式。In XML, the value of an attribute is a de facto string, with the only possible variation being which string encoding format is being used. 在 XAML 中,可以将其他对象元素分配为属性的值。In XAML, you can assign other object elements to be the value of a property. 此功能由属性元素语法启用。This capability is enabled by the property element syntax. 使用elementTypeName中的开始元素标记,而不是在元素标记中指定为特性的属性。propertyName窗体,在中指定属性的值,然后关闭 property 元素。Instead of the property being specified as an attribute within the element tag, the property is specified using an opening element tag in elementTypeName.propertyName form, the value of the property is specified within, and then the property element is closed.

具体而言,语法以左尖括号(<)开头,后跟属性元素语法所包含的类或结构的类型名称。Specifically, the syntax begins with a left angle bracket (<), followed immediately by the type name of the class or structure that the property element syntax is contained within. 后面紧跟一个点(.),然后按属性的名称,然后由一个右尖括号(>)。This is followed immediately by a single dot (.), then by the name of a property, then by a right angle bracket (>). 与特性语法一样,该属性必须存在于指定类型的已声明公共成员中。As with attribute syntax, that property must exist within the declared public members of the specified type. 要分配给属性的值包含在 property 元素中。The value to be assigned to the property is contained within the property element. 通常,值作为一个或多个对象元素提供,因为将对象指定为值是属性元素语法旨在解决的方案。Typically, the value is given as one or more object elements, because specifying objects as values is the scenario that property element syntax is intended to address. 最后,指定相同elementTypeName的等效结束标记。必须提供属性名称组合,正确地进行嵌套并与其他元素标记平衡。Finally, an equivalent closing tag specifying the same elementTypeName.propertyName combination must be provided, in proper nesting and balance with other element tags.

例如,下面是 ButtonContextMenu 属性的属性元素语法。For example, the following is property element syntax for the ContextMenu property of a Button.

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

如果指定的属性类型是基元值类型(如 String)或枚举(其中指定了名称),则属性元素内的值还可以作为内部文本提供。The value within a property element can also be given as inner text, in cases where the property type being specified is a primitive value type, such as String, or an enumeration where a name is specified. 这两种用法有点罕见,因为这两种情况下也可以使用更简单的特性语法。These two usages are somewhat uncommon, because each of these cases could also use a simpler attribute syntax. 用字符串填充属性元素的一个方案是:对于不是 XAML 内容属性但仍用于表示 UI 文本的属性,并且需要在该 UI 文本中显示换行符等特定空白元素。One scenario for filling a property element with a string is for properties that are not the XAML content property but still are used for representation of UI text, and particular white-space elements such as linefeeds are required to appear in that UI text. 特性语法不能保留换行符,但只要有效的空白保留处于活动状态(有关详细信息,请参阅XAML 中的空白处理),属性元素语法就可以。Attribute syntax cannot preserve linefeeds, but property element syntax can, so long as significant white-space preservation is active (for details, see White space processing in XAML). 另一种情况是,可以将X:Uid 指令应用于属性元素,从而将中的值标记为应在 WPF 输出 BAML 或其他技术中本地化的值。Another scenario is so that x:Uid Directive can be applied to the property element and thus mark the value within as a value that should be localized in the WPF output BAML or by other techniques.

属性元素不在 WPF 逻辑树中表示。A property element is not represented in the WPF logical tree. Property 元素只是用于设置属性的特殊语法,而不是具有支持它的实例或对象的元素。A property element is just a particular syntax for setting a property, and is not an element that has an instance or object backing it. (有关逻辑树概念的详细信息,请参阅WPF 中的树。)(For details on the logical tree concept, see Trees in WPF.)

对于支持属性和属性元素语法的属性,这两个语法通常具有相同的结果,尽管微妙之处(如空格处理)在语法上略有不同。For properties where both attribute and property element syntax are supported, the two syntaxes generally have the same result, although subtleties such as white-space handling can vary slightly between syntaxes.

集合语法Collection Syntax

XAML 规范要求 XAML 处理器实现来标识值类型为集合的属性。The XAML specification requires XAML processor implementations to identify properties where the value type is a collection. .NET 中的常规 XAML 处理器实现基于托管代码和 CLR,并通过以下方法之一标识集合类型:The general XAML processor implementation in .NET is based on managed code and the CLR, and it identifies collection types through one of the following:

如果属性的类型是集合,则不需要在标记中将推断的集合类型指定为对象元素。If the type of a property is a collection, then the inferred collection type does not need to be specified in the markup as an object element. 相反,旨在成为集合中的项的元素被指定为属性元素的一个或多个子元素。Instead, the elements that are intended to become the items in the collection are specified as one or more child elements of the property element. 在加载过程中,将每个此类项计算为一个对象,并通过调用隐含集合的 Add 方法将其添加到集合中。Each such item is evaluated to an object during loading and added to the collection by calling the Add method of the implied collection. 例如,StyleTriggers 属性采用专用集合类型 TriggerCollection实现 IListFor example, the Triggers property of Style takes the specialized collection type TriggerCollection, which implements IList. 不需要实例化标记中的 TriggerCollection 对象元素。It is not necessary to instantiate a TriggerCollection object element in the markup. 相反,你可以将一个或多个 Trigger 项指定为 Style.Triggers 属性元素中的元素,其中 Trigger (或派生类)是需要作为强类型和隐式 TriggerCollection的项类型的类型。Instead, you specify one or more Trigger items as elements within the Style.Triggers property element, where Trigger (or a derived class) is the type expected as the item type for the strongly typed and implicit 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 内容属性,本主题的下一部分将对此进行讨论。A property may be both a collection type and the XAML content property for that type and derived types, which is discussed in the next section of this topic.

隐式集合元素在逻辑树表示形式中创建成员,即使它不在标记中显示为元素也是如此。An implicit collection element creates a member in the logical tree representation, even though it does not appear in the markup as an element. 通常,父类型的构造函数对作为其属性之一的集合执行实例化,初始空集合将成为对象树的一部分。Usually the constructor of the parent type performs the instantiation for the collection that is one of its properties, and the initially empty collection becomes part of the object tree.

备注

集合检测不支持泛型列表和字典接口(IList<T>IDictionary<TKey,TValue>)。The generic list and dictionary interfaces (IList<T> and IDictionary<TKey,TValue>) are not supported for collection detection. 但是,可以使用 List<T> 类作为基类,因为它直接实现 IListDictionary<TKey,TValue> 为基类,因为它直接实现 IDictionaryHowever, you can use the List<T> class as a base class, because it implements IList directly, or Dictionary<TKey,TValue> as a base class, because it implements IDictionary directly.

在集合类型的 .NET 参考页中,在 XAML 语法节中,有意省略集合的 object 元素的这一语法被标记为隐式集合语法。In the .NET Reference pages for collection types, this syntax with the deliberate omission of the object element for a collection is occasionally noted in the XAML syntax sections as Implicit Collection Syntax.

除了 root 元素外,XAML 文件中作为另一个元素的子元素嵌套的每个对象元素都确实是以下两种情况之一或全部的元素:其父元素的隐式集合属性的成员或一个元素,该元素指定父元素的 XAML 内容属性的值(将在即将发布的部分中讨论 XAML 内容属性)。With the exception of the root element, every object element in a XAML file that is nested as a child element of another element is really an element that is one or both of the following cases: a member of an implicit collection property of its parent element, or an element that specifies the value of the XAML content property for the parent element (XAML content properties will be discussed in an upcoming section). 换言之,标记页中父元素和子元素的关系实际上是根中的单个对象,根下的每个对象元素都是提供父属性值的单个实例,或者是列中的一个项lection,它也是父级的集合类型属性值。In other words, the relationship of parent elements and child elements in a markup page is really a single object at the root, and every object element beneath the root is either a single instance that provides a property value of the parent, or one of the items within a collection that is also a collection-type property value of the parent. 这种单一根概念是 XML 所共有的,并经常加强加载 XAML 的 Api (如 Load)的行为。This single-root concept is common with XML, and is frequently reinforced in the behavior of APIs that load XAML such as Load.

下面的示例是显式指定的集合(GradientStopCollection)的 object 元素的语法。The following example is a syntax with the object element for a collection (GradientStopCollection) specified explicitly.

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

请注意,并非始终可以显式声明集合。Note that it is not always possible to explicitly declare the collection. 例如,在前面所示的 Triggers 示例中显式声明 TriggerCollection 会失败。For instance, attempting to declare TriggerCollection explicitly in the previously shown Triggers example would fail. 显式声明集合需要集合类必须支持无参数的构造函数,并且 TriggerCollection 没有无参数的构造函数。Explicitly declaring the collection requires that the collection class must support a parameterless constructor, and TriggerCollection does not have a parameterless constructor.

XAML 内容属性XAML Content Properties

XAML 内容语法是一种语法,它仅在将 ContentPropertyAttribute 指定为其类声明的一部分的类上启用。XAML content syntax is a syntax that is only enabled on classes that specify the ContentPropertyAttribute as part of their class declaration. ContentPropertyAttribute 引用作为该类型元素(包括派生类)的内容属性的属性名称。The ContentPropertyAttribute references the property name that is the content property for that type of element (including derived classes). 当由 XAML 处理器处理时,在对象元素的开始标记和结束标记之间找到的任何子元素或内部文本都将被指定为该对象的 XAML 内容属性的值。When processed by a XAML processor, any child elements or inner text that are found between the opening and closing tags of the object element will be assigned to be the value of the XAML content property for that object. 允许你为 content 属性指定显式属性元素,但此用法通常不会显示在 .NET 参考的 "XAML 语法" 部分中。You are permitted to specify explicit property elements for the content property, but this usage is not generally shown in the XAML syntax sections in the .NET reference. 显式/详细方法为标记清晰度或标记样式提供了偶尔的值,但内容属性的目的通常是简化标记,以便可以直接嵌套直观相关的元素。The explicit/verbose technique has occasional value for markup clarity or as a matter of markup style, but usually the intent of a content property is to streamline the markup so that elements that are intuitively related as parent-child can be nested directly. 元素的其他属性的属性元素标记未按严格 XAML 语言定义指定为 "content";它们先前在 XAML 分析器的处理顺序中进行处理,并且不被视为 "内容"。Property element tags for other properties on an element are not assigned as "content" per a strict XAML language definition; they are processed previously in the XAML parser's processing order and are not considered to be "content".

XAML 内容属性值必须是连续的XAML Content Property Values Must Be Contiguous

XAML 内容属性的值必须完全在该对象元素上的任何其他属性元素之前或之后指定。The value of a XAML content property must be given either entirely before or entirely after any other property elements on that object element. 无论 XAML 内容属性的值是指定为字符串,还是指定为一个或多个对象,都是如此。This is true whether the value of a XAML content property is specified as a string, or as one or more objects. 例如,以下标记不会进行分析:For example, the following markup does not parse:

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

这对于本质而言是非法的,因为如果通过使用 content 属性的属性元素语法使此语法变为显式,则内容属性将设置两次:This is illegal essentially because if this syntax were made explicit by using property element syntax for the content property, then the content property would be set twice:

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

例如,如果 content 属性是一个集合,并且子元素与属性元素交错在一起,则这是一个类似的非法示例:A similarly illegal example is if the content property is a collection, and child elements are interspersed with property elements:

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

内容属性和集合语法组合Content Properties and Collection Syntax Combined

为了接受多个对象元素作为内容,内容属性的类型必须特别是集合类型。In order to accept more than a single object element as content, the type of the content property must specifically be a collection type. 类似于集合类型的属性元素语法,XAML 处理器必须标识作为集合类型的类型。Similar to property element syntax for collection types, a XAML processor must identify types that are collection types. 如果元素具有 XAML 内容属性,且 XAML 内容属性的类型是集合,则不需要在标记中将隐含的集合类型指定为对象元素,并且不需要将 XAML 内容属性指定为 el 属性e).If an element has a XAML content property and the type of the XAML content property is a collection, then the implied collection type does not need to be specified in the markup as an object element and the XAML content property does not need to be specified as a property element. 因此,标记中的外观内容模型现在可以将多个子元素作为内容进行分配。Therefore the apparent content model in the markup can now have more than one child element assigned as the content. 下面是 Panel 派生类的内容语法。The following is content syntax for a Panel derived class. 所有 Panel 派生类建立要 Children的 XAML 内容属性,这需要类型 UIElementCollection的值。All Panel derived classes establish the XAML content property to be Children, which requires a value of type 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 的元素。Note that neither the property element for Children nor the element for the UIElementCollection is required in the markup. 这是 XAML 的一项设计功能,使得定义 UIUI 的递归包含元素更直观地表示为具有直接父子元素关系的嵌套元素树,无需干预属性元素标记或集合对象。This is a design feature of XAML so that recursively contained elements that define a UIUI are more intuitively represented as a tree of nested elements with immediate parent-child element relationships, without intervening property element tags or collection objects. 事实上,在设计上,不能以对象元素的形式在标记中显式指定 UIElementCollectionIn fact, UIElementCollection cannot be specified explicitly in markup as an object element, by design. 因为其唯一用途是作为隐式集合,所以 UIElementCollection 不公开公共的无参数构造函数,因此不能将其实例化为对象元素。Because its only intended use is as an implicit collection, UIElementCollection does not expose a public parameterless constructor and thus cannot be instantiated as an object element.

使用 Content 属性混合对象中的属性元素和对象元素Mixing Property Elements and Object Elements in an Object with a Content Property

XAML 规范声明 XAML 处理器可以强制在对象元素中用于填充 XAML 内容属性的对象元素必须是连续的,且不能混合使用。The XAML specification declares that a XAML processor can enforce that object elements that are used to fill the XAML content property within an object element must be contiguous, and must not be mixed. 对混合属性元素和内容的这一限制由 WPFWPF 的 XAML 处理器强制执行。This restriction against mixing property elements and content is enforced by the WPFWPF XAML processors.

您可以将一个子对象元素作为对象元素中的第一个直接标记。You can have a child object element as the first immediate markup within an object element. 然后,可以引入属性元素。Then you can introduce property elements. 或者,您可以指定一个或多个属性元素,然后指定 content,再指定更多属性元素。Or, you can specify one or more property elements, then content, then more property elements. 但一旦属性元素跟随内容,就不能再引入任何内容,只能添加属性元素。But once a property element follows content, you cannot introduce any further content, you can only add property elements.

此内容/属性元素顺序要求不适用于用作内容的内部文本。This content / property element order requirement does not apply to inner text used as content. 但是,它仍是一个很好的标记样式来保持内部文本连续,因为如果属性元素与内部文本交错,则很难在标记中直观地检测到有效的空白。However, it is still a good markup style to keep inner text contiguous, because significant white space will be difficult to detect visually in the markup if property elements are interspersed with inner text.

XAML 命名空间XAML Namespaces

上述语法示例均未指定默认 XAML 命名空间之外的 XAML 命名空间。None of the preceding syntax examples specified a XAML namespace other than the default XAML namespace. 在典型的 WPFWPF 应用程序中,默认的 XAML 命名空间指定为 WPFWPF 命名空间。In typical WPFWPF applications, the default XAML namespace is specified to be the WPFWPF namespace. 可以指定除默认 XAML 命名空间之外的 XAML 命名空间,并且仍使用类似的语法。You can specify XAML namespaces other than the default XAML namespace and still use similar syntax. 但然后,在默认 XAML 命名空间内无法访问的类的任何位置,该类名前面必须带有 XAML 命名空间的前缀,才能映射到相应的 CLR 命名空间。But then, anywhere where a class is named that is not accessible within the default XAML namespace, that class name must be preceded with the prefix of the XAML namespace as mapped to the corresponding CLR namespace. 例如,<custom:Example/> 是用于实例化 Example 类的实例的对象元素语法,其中包含该类的 CLR 命名空间(也可能是包含支持类型的外部程序集信息)以前映射到 custom作为.For example, <custom:Example/> is object element syntax to instantiate an instance of the Example class, where the CLR namespace containing that class (and possibly the external assembly information that contains backing types) was previously mapped to the custom prefix.

有关 XAML 命名空间的详细信息,请参阅WPF xaml 的 Xaml 命名空间和命名空间映射For more information about XAML namespaces, see XAML Namespaces and Namespace Mapping for WPF XAML.

标记扩展Markup Extensions

XAML 定义了一个标记扩展编程实体,该实体启用对字符串属性值或对象元素的一般 XAML 处理器处理的转义,并将处理推迟到后备类中。XAML defines a markup extension programming entity that enables an escape from the normal XAML processor handling of string attribute values or object elements, and defers the processing to a backing class. 使用特性语法时标识 XAML 处理器的标记扩展的字符为左大括号({),后跟右大括号(})以外的任何字符。The character that identifies a markup extension to a XAML processor when using attribute syntax is the opening curly brace ({), followed by any character other than a closing curly brace (}). 左大括号后面的第一个字符串必须引用提供特定扩展行为的类,如果子字符串属于真实的类名称,则引用可能会忽略子字符串 "Extension"。The first string following the opening curly brace must reference the class that provides the particular extension behavior, where the reference may omit the substring "Extension" if that substring is part of the true class name. 此后,可能会出现一个空格,然后将每个后续字符用作扩展实现的输入,直至遇到右大括号。Thereafter, a single space may appear, and then each succeeding character is used as input by the extension implementation, up until the closing curly brace is encountered.

.NET XAML 实现使用 MarkupExtension 抽象类作为所有 WPFWPF 支持的标记扩展以及其他框架或技术的基础。The .NET XAML implementation uses the MarkupExtension abstract class as the basis for all of the markup extensions supported by WPFWPF as well as other frameworks or technologies. WPFWPF 专门实现的标记扩展通常用于提供引用其他现有对象的方法,或者用于对将在运行时计算的对象进行延迟引用。The markup extensions that WPFWPF specifically implements are often intended to provide a means to reference other existing objects, or to make deferred references to objects that will be evaluated at run time. 例如,通过指定 {Binding} 标记扩展来替换特定属性通常会采用的值来完成简单的 WPF 数据绑定。For example, a simple WPF data binding is accomplished by specifying the {Binding} markup extension in place of the value that a particular property would ordinarily take. 很多 WPF 标记扩展为属性启用了属性语法,在这种情况下,不可能出现特性语法。Many of the WPF markup extensions enable an attribute syntax for properties where an attribute syntax would not otherwise be possible. 例如,Style 对象是一个相对复杂的类型,它包含一系列嵌套的对象和属性。For example, a Style object is a relatively complex type that contains a nested series of objects and properties. WPF 中的样式通常定义为 ResourceDictionary中的资源,然后通过请求资源的两个 WPF 标记扩展之一进行引用。Styles in WPF are typically defined as a resource in a ResourceDictionary, and then referenced through one of the two WPF markup extensions that request a resource. 标记扩展将属性值的计算延迟为资源查找,并支持在特性语法中提供 Style 属性的值,采用类型 Style,如下面的示例中所示:The markup extension defers the evaluation of the property value to a resource lookup and enables providing the value of the Style property, taking type Style, in attribute syntax as in the following example:

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

此处 StaticResource 标识提供标记扩展实现的 StaticResourceExtension 类。Here, StaticResource identifies the StaticResourceExtension class providing the markup extension implementation. 下一个字符串 MyStyle 用作非默认 StaticResourceExtension 构造函数的输入,其中,从扩展字符串中获取的参数声明所请求的 ResourceKeyThe next string MyStyle is used as the input for the non-default StaticResourceExtension constructor, where the parameter as taken from the extension string declares the requested ResourceKey. MyStyle 应为定义为资源的 Style 的 " x:Key " 值。MyStyle is expected to be the x:Key value of a Style defined as a resource. StaticResource 标记扩展用法请求资源用于在加载时通过静态资源查找逻辑提供 Style 属性值。The StaticResource Markup Extension usage requests that the resource be used to provide the Style property value through static resource lookup logic at load time.

有关标记扩展的详细信息,请参阅标记扩展和 WPF XAMLFor more information about markup extensions, see Markup Extensions and WPF XAML. 有关在常规 .NET XAML 实现中启用的标记扩展和其他 XAML 编程功能的引用,请参阅XAML 命名空间(x:)语言功能For a reference of markup extensions and other XAML programming features enabled in the general .NET XAML implementation, see XAML Namespace (x:) Language Features. 有关特定于 WPF 的标记扩展,请参阅WPF XAML 扩展For WPF-specific markup extensions, see WPF XAML Extensions.

附加属性Attached Properties

附加属性是 XAML 中引入的一种编程概念,其中属性可由特定类型拥有和定义,但设置为任意元素上的特性或属性元素。Attached properties are a programming concept introduced in XAML whereby properties can be owned and defined by a particular type, but set as attributes or property elements on any element. 附加属性的主要方案是允许标记结构中的子元素向父元素报告信息,而无需跨所有元素广泛共享对象模型。The primary scenario that attached properties are intended for is to enable child elements in a markup structure to report information to a parent element without requiring an extensively shared object model across all elements. 相反,附加属性可由父元素用来向子元素报告信息。Conversely, attached properties can be used by parent elements to report information to child elements. 有关附加属性以及如何创建您自己的附加属性的详细信息,请参阅附加属性概述For more information on the purpose of attached properties and how to create your own attached properties, see Attached Properties Overview.

附加属性使用的语法在表面上类似于属性元素语法,因为你还需要指定typeNamepropertyName组合。Attached properties use a syntax that superficially resembles property element syntax, in that you also specify a typeName.propertyName combination. 有两个重要的差异:There are two important differences:

  • 您可以使用typeNamepropertyName组合,即使通过特性语法设置附加属性也是如此。You can use the typeName.propertyName combination even when setting an attached property through attribute syntax. 附加属性是在特性语法中限定属性名称的唯一情况。Attached properties are the only case where qualifying the property name is a requirement in an attribute syntax.

  • 还可以对附加属性使用属性元素语法。You can also use property element syntax for attached properties. 但对于典型的属性元素语法,指定的类型名称是包含 property 元素的对象元素。However, for typical property element syntax, the typeName you specify is the object element that contains the property element. 如果你引用附加属性,则typeName是定义附加属性的类,而不是包含对象元素。If you are referring to an attached property, then the typeName is the class that defines the attached property, not the containing object element.

附加事件Attached Events

附加事件是 XAML 中引入的另一种编程概念,其中事件可以由特定类型定义,但处理程序可以附加到任何对象元素上。Attached events are another programming concept introduced in XAML where events can be defined by a specific type, but handlers may be attached on any object element. 在 WOF 实现中,定义附加事件的类型通常为定义服务的静态类型,有时这些附加事件由公开服务的类型中的路由事件别名公开。In the WOF implementation, often the type that defines an attached event is a static type that defines a service, and sometimes those attached events are exposed by a routed event alias in types that expose the service. 附加事件的处理程序通过特性语法指定。Handlers for attached events are specified through attribute syntax. 与附加事件一样,为附加事件扩展特性语法以允许typeName事件名称用法,其中typeName是为附加事件基础结构提供 AddRemove 事件处理程序访问器的类 ,而事件名称是事件名称。As with attached events, the attribute syntax is expanded for attached events to allow a typeName.eventName usage, where typeName is the class that provides Add and Remove event handler accessors for the attached event infrastructure, and eventName is the event name.

XAML 根元素的解析Anatomy of a XAML Root Element

下表显示了一个典型的 XAML 根元素,该元素向下分解,其中显示了根元素的特定属性:The following table shows a typical XAML root element broken down, showing the specific attributes of a root element:

<Page 根元素的打开对象元素Opening object element of the root element
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 默认的(WPFWPF) XAML 命名空间The default (WPFWPF) XAML namespace
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" XAML 语言 XAML 命名空间The XAML language XAML namespace
x:Class="ExampleNamespace.ExampleCode" 分部类声明,它将标记连接到为分部类定义的任何代码隐藏The partial class declaration that connects markup to any code-behind defined for the partial class
> 根的对象元素的结尾。End of object element for the root. 对象尚未关闭,因为元素包含子元素Object is not closed yet because the element contains child elements

可选和推荐 XAML 用法Optional and Nonrecommended XAML Usages

以下各节介绍 XAML 处理器在技术上受支持的 XAML 用法,但产生的详细程度或其他美观问题会影响在开发包含 XAML 源的应用程序时可读取的 XAML 文件。The following sections describe XAML usages that are technically supported by XAML processors, but that produce verbosity or other aesthetic issues that interfere with XAML files remaining human-readable when you develop applications that contain XAML sources.

可选属性元素用法Optional Property Element Usages

可选属性元素用法包括显式写出 XAML 处理器认为隐式的元素内容属性。Optional property element usages include explicitly writing out element content properties that the XAML processor considers implicit. 例如,在声明 Menu的内容时,可以选择将 MenuItems 集合显式声明为 <Menu.Items> 属性元素标记,并将每个 MenuItem 放置在 <Menu.Items>,而不是使用隐式 XAML 处理器行为,Menu 的所有子元素必须是 MenuItem 并置于 Items 集合中。For example, when you declare the contents of a Menu, you could choose to explicitly declare the Items collection of the Menu as a <Menu.Items> property element tag, and place each MenuItem within <Menu.Items>, rather than using the implicit XAML processor behavior that all child elements of a Menu must be a MenuItem and are placed in the Items collection. 有时,可选用法可帮助以直观方式阐明标记中所表示的对象结构。Sometimes the optional usages can help to visually clarify the object structure as represented in the markup. 或者有时,显式属性元素使用可以避免在技术上正常运行的标记,但在视觉上混乱,如属性值中的嵌套标记扩展。Or sometimes an explicit property element usage can avoid markup that is technically functional but visually confusing, such as nested markup extensions within an attribute value.

完整的 typeName 成员限定属性Full typeName.memberName Qualified Attributes

TypeName。属性的成员名称格式实际上比路由事件事例更通用。The typeName.memberName form for an attribute actually works more universally than just the routed event case. 但在其他情况下,该窗体是多余的,如果仅出于标记样式和可读性的原因,应避免这样做。But in other situations that form is superfluous and you should avoid it, if only for reasons of markup style and readability. 在下面的示例中,对 Background 属性的三个引用都完全等效:In the following example, each of the three references to the Background attribute are completely equivalent:

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

Button.Background 工作,因为 Button 上的该属性的限定查找成功(Background 从控件继承),并且 Button 是对象元素或基类的类。Button.Background works because the qualified lookup for that property on Button is successful (Background was inherited from Control) and Button is the class of the object element or a base class. Control.Background 可行,因为 Control 类实际定义 Background,而 ControlButton 的基类。Control.Background works because the Control class actually defines Background and Control is a Button base class.

但是,以下类型名称为。成员名称形式的示例不起作用,因此会以注释形式显示:However, the following typeName.memberName form example does not work and is thus shown commented:

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

LabelControl的另一个派生类,并且如果你在 Label 对象元素中指定了 Label.Background,则此用法将起作用。Label is another derived class of Control, and if you had specified Label.Background within a Label object element, this usage would have worked. 但是,因为 Label 不是 Button的类或基类,所以指定的 XAML 处理器行为将作为附加属性处理 Label.BackgroundHowever, because Label is not the class or base class of Button, the specified XAML processor behavior is to then process Label.Background as an attached property. Label.Background 不是可用的附加属性,且此使用失败。Label.Background is not an available attached property, and this usage fails.

b 属性元素baseTypeName.memberName Property Elements

typeName的方式类似。成员名称形式适用于特性语法, b成员名称语法适用于属性元素语法。In an analogous way to how the typeName.memberName form works for attribute syntax, a baseTypeName.memberName syntax works for property element syntax. 例如,下面的语法有效:For instance, the following syntax works:

<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中。Here, the property element was given as Control.Background even though the property element was contained in Button.

但就像类型名称一样。属性的成员名称形式b成员名称在标记中的样式不佳,你应避免这样做。But just like typeName.memberName form for attributes, baseTypeName.memberName is poor style in markup, and you should avoid it.

请参阅See also