电脑故障

位置:IT落伍者 >> 电脑故障 >> 浏览文章

理解XAML语法术语


发布日期:2021/2/10
 

本主题定义用来描述可扩展应用程序标记语言 (XAML) 语法的各个元素的术语这些术语将在本软件开发工具包 (SDK) 的其余部分中经常用到本主题扩展了 XAML 概述中所介绍的基本术语

XAML 语法术语的起源

此处定义的 XAML 语法术语在 XAML 语言规范中也有定义或引用XAML 是一种基于 XML 且遵循 XML 结构规则的语言其中的术语共享自或基于描述 XML 语言或 XML 文档对象模型 (DOM) 时的常用术语

对象元素语法

对象元素语法是一种 XAML 标记语法它通过声明 XML 元素来实例化公共语言运行库 (CLR) 类或结构此语法与其他标记语言(例如 HTML)的元素语法相似对象元素语法以左尖括号 (<) 开头其后紧跟正进行实例化的类或结构的类型名称类型名称后面可以有零个或多个空格对于对象元素还可以声明零个或多个属性并用一个或多个空格来分隔每个属性名=最后必须存在下列一种情况

元素和标记必须用正斜槓 (/) 和紧跟的右尖括号 (>) 结尾

开始标记必须以右尖括号 (>) 结尾其他对象元素属性元素或内部文本可以跟在开始标记后面对象元素还必须存在等效的结束标记并与其他开始标记/结束标记对形成正确的嵌套和平衡

例如下面的示例是一个对象元素语法该语法实例化 Button 类的一个新实例而且还指定了一个 Name 属性及其值

下面的示例是一个还包括可扩展应用程序标记语言 (XAML) 内容属性语法的对象元素语法其中包含的内部文本将用来设置 TextBox 可扩展应用程序标记语言 (XAML) 内容属性 Text

属性语法

属性语法是一种 XAML 标记语法该语法通过针对元素声明属性 (Attribute) 来设置属性 (Property) 值或者命名事件的事件处理程序元素总是通过对象元素语法来声明属性名必须与属性或事件的 CLR 成员名称相匹配属性名后面是赋值运算符 (=)属性值必须是一个用双引号 () 引起来的字符串

为了能够通过属性语法进行设置属性必须是公共的可读写的而且必须具有一个可以由 XAML 处理器实例化或引用的属性值类型对于事件来说事件必须是公共的而且必须具有一个公共委托属性或事件必须是由包含对象元素实例化的类或结构的成员

属性值由下面的操作之一按照如下处理顺序进行填充

如果 XAML 处理器遇到一个大括号或者遇到一个从 MarkupExtension 派生的对象元素则将首先计算所引用的标记扩展(而不是将该扩展作为字符串来处理)而且将使用由标记扩展返回的对象在许多情况下由标记扩展返回的对象将是对现有对象的引用或者是一个将计算推迟到运行时的表达式而不是一个新对象

如果该属性 (Property) 是用指定的 TypeConverter 声明的或者该属性 (Property) 的值类型是用属性 (Attribute) 化 TypeConverter 声明的则该属性 (Attribute) 的字符串值将作为转换输入提交到类型转换器该转换器将返回一个新的对象实例

如果没有 TypeConverter则将尝试直接转换为属性类型最后一个级别是直接在基元类型之间转换或者在枚举中检查名称(这将返回匹配的值)

例如在使用上面所显示的标记时可以使用下面的属性 (Attribute) 语法示例为

Name 属性 (Property) 赋予字符串值

Name 属性是 Button 类的成员表的成员Button 是用来定义 Name 的 FrameworkElement 类的派生类

属性值的处理

包含在左引号和右引号之间的字符串值是由 XAML 处理器处理的对于属性来说默认处理行为是由基础 CLR 属性的类型确定的如果该属性 (Property) 是基元类型则会基于字符串到相关基元类型的隐式转换来赋予属性 (Attribute) 值如果该属性是一个枚举则字符串会被视为由该枚举定义的名称而且将从枚举中返回匹配的值如果该属性 (Property) 既不是基元类型又不是枚举则属性 (Attribute) 值必须由针对该属性 (Property) 本身或者目标类型声明的类型转换器来处理类型转换器必须提供一个能够接受字符串的转换机制该转换机制必须生成基础 CLR 属性类型的实例还可以通过标记扩展来推迟转换步骤

枚举属性值

XAML 中的枚举值由 Enum 结构的本机方法在内部处理

对于无标志的枚举值本机行为是处理属性值的字符串并将它解析为某个枚举值您不必像在代码中那样指定格式为枚举值 的枚举而是仅指定值枚举 将从所设置属性的类型推断如果您指定格式为枚举值 的属性它将无法正确解析

对于按标志枚举该行为基于 Enum::Parse 方法您可以通过用逗号分隔每个值来为按标志枚举指定多个值但是您不能合并不按标志的枚举值例如不能试图使用逗号语法来创建作用于无标志枚举多个条件的 Trigger

在 WPF 中能够支持 XAML 中可设置属性的按标志枚举极为罕见但是StyleSimulations 就是这样的一个枚举例如可以使用逗号分隔的按标志属性语法来修改在 Glyphs 类的Remarks(备注)部分中提供的示例StyleSimulations = BoldSimulation 可能会变成 StyleSimulations = BoldSimulationItalicSimulationKeyBinding::Modifiers 是另一个属性在该属性中可以指定多个枚举值但是此属性是一个特例因为 ModifierKeys 枚举支持其自身的类型转换器修饰符的类型转换器使用加号 (+) 而不是逗号 () 作为分隔符因此在标记中支持用更传统的语法来表示组合键(如Ctrl+Alt

属性引用和事件成员名称引用

在指定属性 (Attribute) 时可以引用您已经为包含对象元素实例化的 CLR 类型的成员表中存在的任何属性 (Property) 或事件

或者可以独立于包含对象元素来引用附加属性或附加事件

对于可通过默认命名空间访问的任何对象中的任何事件还可以通过使用类型名事件 部分限定名来命名此语法支持为路由事件附加处理程序在路由事件中处理程序旨在处理子元素中的事件路由但是父元素在其成员表中并不拥有该事件此语法与附加事件语法相似但此处的事件不是真正的附加事件相反您引用的是具有限定名称的事件

属性 (Property) 名有时作为属性 (Attribute) 值提供而不是作为属性 (Attribute) 名提供属性 (Property) 名还可以包括限定符例如以所有者类型依赖项属性名称 格式指定的属性在 XAML 中编写样式或模板时此情况较为常见以属性 (Attribute) 值形式提供的属性 (Property) 名具有不同的处理规则这些规则由所设置的属性 (Property) 类型以及某些上下文因素(如样式或模板是否具有目标类型)来控制

当属性 (Attribute) 值描述属性 (Property) 之间的关系时也可以使用属性 (Property) 名此功能可用于数据绑定和演示图板目标而且由 PropertyPath 类及其类型转换器启用

属性元素语法

属性元素语法是一种与基本 XML 语法稍有偏离的语法在 XML 中属性值是一个实际的字符串唯一可能的变化是使用除 UTF 之外的哪种字符串编码格式在 XAML 中可以指定其他对象元素作为属性值此功能由属性元素语法来启用不将属性 (Property) 指定为元素标记中的一个属性 (Attribute)而是使用元素的开始标记指定格式为元素类型名称属性名 的属性 (Property)再指定属性 (Property) 值然后结束属性元素

具体而言该语法以左尖括号 (<) 开头其后紧跟包含属性元素语法的类或结构的类型名称类型名称后面紧跟一个点 ()再后面是必须在指定类型的成员表中存在的属性名最后面是一个右尖括号 (>)要赋给属性的值包含在相应的属性元素中通常值作为一个或多个对象元素提供因为将对象指定为值正是属性元素语法应当实现的方案最后必须提供一个等效的结束标记来指定同一个元素类型名称属性名称 组合并与其他元素标记对形成正确的嵌套和平衡例如下面的属性元素语法针对的是 Button 的 ContextMenu 属性

值也可以作为内部文本提供但是只有当指定的属性类型是基元值类型(如 String)或者是指定了名称的枚举时才能这样做这两个用法不太常见因为这两种情况都还支持属性语法用字符串填充属性元素的一个方案是对于不是 XAML 内容属性但是仍用于表示 UI 文本的属性UI 文本中必须出现特定的空白元素(如换行符)属性 (Attribute) 语法不能保留换行符但是属性 (Property) 元素语法可以保留换行符不过前提是用来保留大量空白的功能处于活动状态

属性元素不属于逻辑树它不是由实例支持的元素而只是一个用来设置属性的特定语法

集合类型的属性元素语法

XAML 规范要求所实现的 XAML 处理器能够标识值类型是集合的属性WPF 实现基于托管代码它的 XAML 处理器通过下列操作之一来标识集合类型

实现 IList

实现 IDictionary

从 Array 派生

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

属性可以既是一个集合类型又是该类型和派生类型的 XAML 内容属性

隐式集合元素会在逻辑树中创建一个成员即使它在标记中不显示为元素也是如此通常所拥有类型的构造函数针对作为其属性之一的集合执行实例化这会将该集合添加到树中

说明

由 WPF XAML 处理器执行的集合检测功能不支持泛型列表和字典接口(IList<(Of <(T>)>) 和 IDictionary<(Of <(TKey TValue>)>))但是可以将 List<(Of <(T>)>) 类用作基类(因为它直接实现 IList)或者将 Dictionary<(Of <(TKey TValue>)>) 用作基类(因为它直接实现 IDictionary)

XAML 内容语法

XAML 内容语法仅在将 ContentPropertyAttribute 指定为其类声明一部分的类上启用ContentPropertyAttribute 需要一个按名称指定属性的参数而该属性名称被定义为这种类型元素(包括派生的类)的内容属性为此指定的属性是元素的 XAML 内容属性在由 XAML 处理器处理时在元素的开始标记和结束标记之间找到的任何子元素或内部文本将被指定为该 XAML 内容属性的值元素的属性元素标记不按照这种方式赋值它们是先进行处理而且不被视为内容

正如对于任何其他属性一样对象的 XAML 内容属性将属于特定类型该类型可以是 Object 类型该内容属性的类型可帮助定义对象的内容模型例如鑒于任何对象都可以变为内容Object 的类型是松散的但是即使这种松散类型也要求内容必须是单个对象该单个对象可以是集合对象

但是即便如此也只能将一个这样的集合对象指定为内容

特定类型的内容模型在该类型的类页面上进行描述或者编写成类型系列的单独概念性主题中并与每个相关的类型引用建立链接

集合类型的内容语法

为了接受多个对象元素(或内部文本)作为内容内容属性的类型必须是明确的集合类型与集合类型的属性元素语法相似XAML 处理器必须标识作为集合类型的类型如果某个元素具有 XAML 内容属性则该 XAML 内容属性的类型是集合不必在标记中将隐含集合类型指定为对象元素也不必将 XAML 内容属性指定为属性元素因此标记中明显的内容模型现在可以将多个子元素作为指定为内容下面是 Panel 子类的内容语法所有的 Panel 派生类都建立要成为 Children 的 XAML 内容属性这需要一个类型为 UIElementCollection 的值

请注意标记中既不需要 Children 的属性元素也不需要 UIElementCollection 的元素这是 XAML 的设计特征其目的在于使用直接的父子元素关系将那些用来定义 UI 的递归包含的元素更直观地表示为嵌套元素树而不必对属性元素标记或集合对象进行外部干预实际上按照设计UIElementCollection 在标记中不能指定为对象元素由于 UIElementCollection 唯一的用途就是作为隐式集合因此它不公开公共的默认构造函数因此不能实例化为对象元素

在具有内容属性的对象中混合使用属性元素和对象元素

XAML 规范声明 XAML 处理器可以进行如下强制用来填充某个对象元素中 XAML 内容属性的对象元素必须是连续的而且不得混合使用对于混合使用属性元素和内容的这一限制是由 WPF XAML 处理器强制的

可以将子对象元素作为某个对象元素中的第一个直接标记然后可以引入属性元素也可以指定一个或多个属性元素接着指定内容然后指定多个属性元素但是一旦内容后面跟有属性元素您就不能进一步引入任何内容而只能引入其他属性元素

这个内容/属性元素顺序要求不适用于用作内容的内部文本然而这仍然是使内部文本保持连续的不错的标记样式原因是如果属性元素与内部文本交错分布则很难直观地检测标记中的大量空白

附加属性

附加属性是 XAML 中引入的一个编程概念借此属性可以由类型拥有和定义但可以在任何元素上设置附加属性所面向的主要方案就是允许元素树中的子元素向父元素报告信息而不要求使用在所有的元素之间广泛共享的对象模型相反附加属性可以由任何父元素用来向子元素报告信息

附加属性使用的语法在表面上与属性元素语法非常相似因为您还需要指定类型名属性名 组合二者有两个重要的差异

即使在通过属性语法设置附加属性时也可以使用类型名属性名 组合只有附加属性 (Property) 才要求属性 (Attribute) 语法中使用限定属性 (Property) 名

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

附加事件

附加事件是 XAML 中引入的另一个编程概念事件可以由类型定义但是处理程序可以附加到任何对象上用来定义附加事件的类型通常是用来定义服务的静态类型这些附加事件有时由用来公开服务的类型中的路由事件别名公开附加事件的处理程序是通过属性语法指定的正如对于附加事件一样可以扩展附加事件的属性语法以便允许使用类型名事件名其中类型名 是为附加事件基础结构提供 Add 和 Remove 事件处理程序访问器的类事件名 是事件名称

XML 命名空间

上面的所有语法示例均未指定默认命名空间以外的命名空间在典型的 WPF 应用程序中默认命名空间被指定为 WPF 命名空间您可以指定默认命名空间以外的命名空间而且仍使用实质上同类的语法但是只要命名了无法在默认命名空间中访问的类该类的名称就必须以用来映射对应 CLR 命名空间的 XML 命名空间的前缀作为开头例如 是一种用来实例化 MyElement 类的实例的对象元素语法其中包含该类的 CLR 命名空间(可能还有包含该命名空间的外部程序集)以前映射到 custom 前缀

标记扩展

XAML 定义了一个标记扩展编程实体该实体允许从 XAML 处理器对属性或对象元素的常规处理中进行转义将该处理转给支持类WPF 对 XAML 处理器的实现将 MarkupExtension 抽象类用作由 WPF 支持的所有标记扩展的基础在使用属性语法时用来标识 XAML 处理器的标记扩展的字符是左大括号 ({)其后是右大括号 (}) 以外的任何字符左大括号后面的第一个字符串必须引用用来提供特定扩展行为的类如果子字符串Extension是实际类名的一部分则该引用可以省略这个子字符串该类后面可能会出现一个空格该空格后面的每个字符都可以由所实现的扩展用作输入直到遇到右大括号在使用属性语法时WPF 中标记扩展的主要用途是提供一种方法来引用其他已经存在的对象或者将引用转给将在运行时计算的对象例如可以指定用 {Binding} 标记扩展来代替给定的属性通常将使用的值类型从而完成简单的数据绑定对于无法以其他方式使用属性 (Attribute) 语法的属性 (Property)许多标记扩展都允许使用属性 (Attribute) 语法例如Style 对象是一个相对复杂的引用类型其中包含几个其他属性每个属性都还采用 byref 对象(而非基元)但是样式通常作为资源来创建之后将通过请求资源的两个标记扩展之一来引用该扩展将对属性 (Property) 值的计算推迟到资源查找时允许在属性 (Attribute) 语法中提供 Style 属性 (Property) 的值并采用 Style 类型如下所示

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

可选的和不建议的 XAML 用法

属性元素的可选用法

属性元素的可选用法包括具体地拼出由 XAML 处理器视为隐式的元素内容属性例如当您声明 Menu 的内容时可以选择将 Menu 的 Items 集合显式声明为 属性元素标记并将每个 MenuItem 放在 而不是使用隐式的 XAML 处理器行为(即Menu 的所有子元素都必须是 MenuItem 而且放在 Items 集合中)有时这个可选用法可以帮助以可视方式阐明标记中所表示的对象结构

或者属性元素的隐式用法有时可以避免使用在技术上具有功能但是在视觉上容易引起混淆(如在属性值中嵌套标记扩展)的标记

mberName 全限定属性

使用属性的类型名成员名 格式实际上比仅仅使用路由事件的情况更为普遍但是在其他应用程序中如果只是为了实现标记样式和可读性则该格式是多余的您应当避免使用它在下面的示例中对 Background 属性的三个引用是完全等效的

ButtonBackground 之所以适用是因为在 Button 上对于该属性的查找是成功的(Background 是从 Control 继承的)而且 Button 是对象元素的类或者是基类ControlBackground 之所以适用是因为 Control 类实际上定义 Background而且 Control 是一个 Button 基类

但是下面的类型名成员名 格式示例并不适用因此显示为已注释掉

Label 是 Control 的另一个派生类而且如果在 Label 对象元素中指定了 LabelBackground则该用法将适用但是由于 Label 不是 Button 的类或基类因此指定的 XAML 处理器行为是随后以附加属性形式处理 LabelBackgroundLabelBackground 不是附加属性因此该用法将失败

mberName 属性元素

与类型名成员名 格式如何适用于属性语法相似基类型名称成员名 语法适用于属性元素语法例如下面的语法适用

在这里即使属性元素包含在 Button 中属性元素也会以 ControlBackground 形式提供

但是正如属性的类型名成员名 格式一样基类型名称成员名 在标记中是很差的样式您应当避免将其用于设置样式

上一篇:编程高手 DotNet异步消息处理方法

下一篇:铁路售票系统应用软件需求分析报告