2024年2月8日发(作者:)
XAML 概述 (WPF)
本主题介绍 XAML 语言的功能,并演示如何使用 XAML 编写 Windows Presentation
Foundation (WPF) 应用程序。本主题专门介绍 WPF 实现的 XAML。 XAML 本身是一个比 WPF 大的语言概念。
本主题包括下列各节。
什么是 XAML?
XAML 语法概述
XAML 中的大小写和空白
标记扩展
类型转换器
XAML 根元素和 XAML 命名空间
XAML 中的自定义前缀和自定义类型
事件和 XAML 代码隐藏
XAML 命名元素
附加属性和附加事件
基类型和 XAML
XAML 安全性
从代码中加载 XAML
接下来的内容
相关主题
什么是 XAML?
XAML 是一种声明性标记语言。如同应用于 .NET Framework 编程模型一样,XAML 简化了为 .NET Framework 应用程序创建 UI 的过程。您可以在声明性 XAML 标记中创建可见的 UI 元素,然后使用代码隐藏文件(通过分部类定义与标记相连接)将 UI 定义与运行时逻辑相分离。 XAML 直接以程序集中定义的一组特定后备类型表示对象的实例化。这与大多数其他标记语言不同,后者通常是与后备类型系统没有此类直接关系的解释语言。
XAML 实现了一个工作流,通过此工作流,各方可以采用不同的工具来处理应用程序的 UI
和逻辑。
以文本表示时,XAML 文件是通常具有.xaml扩展名的 XML 文件。可通过任何 XML 编码对文件进行编码,但通常编码为 UTF-8。
下面的示例演示如何创建作为 UI 一部分的按钮。此示例的目的仅在于供您初步了解
XAML 是如何表示常用 UI 编程形式的(它不是一个完整的示例)。
XAML
XAML 语法概述
下面的章节介绍 XAML 语法的基本形式,并提供一个简短的标记示例。这些章节并不提供每个语法形式的完整信息,例如这些语法如何在后备类型系统中表示。有关本主题中介绍的每种语法形式在 XAML 语法中的详情的更多信息,请参见XAML 语法详述。
如果您以前熟悉 XML 语言,则下面几节中的很多材料对您而言都是基础知识。这是
XAML 的其中一个基本设计原则的结果。 XAML 语言定义它自己的概念,但这些概念在
XML 语言和标记形式内发挥作用。
XAML 对象元素
对象元素通常声明类型的实例。该类型在为以 XAML 为语言的技术提供后备类型的程序集中定义。
对象元素语法始终以左尖括号 (<) 开头,后跟要创建实例的类型的名称。(该名称可能包含前缀,前缀的概念会在后面解释。)在此之后,您可以选择声明该对象元素的特性。要完成对象元素标记,请以右尖括号 (>) 结尾。您也可以使用不含任何内容的自结束形式,方法是用一个正斜杠后接一个右尖括号 (/>) 来完成标记。例如,请再次查看前面演示的标记代码段:
XAML
此示例指定了两个对象元素:
处理指令来创建一个新实例。每个实例都是在分析和加载 XAML 时通过调用基础类型的默认构造函数来创建的。
特性语法(属性)
对象的属性通常可表示为对象元素的特性。特性语法命名在特性语法中设置的属性,后跟赋值运算符 (=)。特性的值始终以包含在引号中的字符串的形式进行指定。
特性语法是最简单有效的属性设置语法,并且对于曾使用过标记语言的开发人员而言在使用中是最直观的语法。例如,以下标记将创建一个具有红色文本和蓝色背景的按钮,还将创建指定为Content的显示文本。
XAML
属性元素语法
对于对象元素的某些属性,特性语法是不可能实现的,因为无法在特性语法的引号和字符串限制内充分地表达提供属性值所必需的对象或信息。对于这些情况,可以使用另一个语法,即属性元素语法。
属性元素开始标记的语法为<类型名称.属性名称>。通常,该标记的内容是类型的一个对象元素,属性会将该元素作为其值。指定内容之后,必须用一个结束标记结束属性元素。结束标记的语法为类型名称.属性名称>。
如果可以使用特性语法,那么使用特性语法通常更为方便,且能够实现更为精简的标记,但这通常只是一个风格的问题,而不属于技术限制。下面的示例演示了在前面的特性语法示例中设置的相同属性,但这次对Button的所有属性使用了属性元素语法。
XAML
This is a button
集合语法
XAML 语言包含一些优化,可以生成可读性更好的标记。其中的一项优化是:如果某个特定属性采用集合类型,则您在标记中声明为该属性的值内的子元素的项将成为集合的一部分。在这种情况下,子对象元素的集合是设置为集合属性的值。
下面的示例演示为GradientStops属性设置值的集合语法:
XAML
XAML 内容属性
XAML 指定了一个语言功能,通过该功能,一个类可以指定它的一个且仅一个属性为
XAML 内容属性。该对象元素的子元素用于设置该内容属性的值。换言之,仅对内容属性而言,您可以在 XAML 标记中设置该属性时省略属性元素,并在标记中生成更直观的父级/子级形式。
例如,Border指定内容属性Child。系统处理下面两个Border元素的方式相同。第一个元素利用了内容属性语法而省略了属性元素。第二个元素显式标明。
XAML
<>
>
作为 XAML 语言的规则,XAML 内容属性的值必须完全在该对象元素的其他任何属性元素之前或之后指定。例如,下面的标记无法进行编译:
blue button
有关 XAML 内容属性的此项限制的更多信息,请参见XAML 语法详述的“XAML 内容属性”一节。
文本内容
有少量 XAML 元素可直接将文本作为其内容来处理。若要实现此功能,必须满足以下条件之一:
类必须声明一个内容属性,并且该内容属性必须是可赋值给字符串的类型(该类型可以是Object)。例如,任何ContentControl都将Content用作其内容属性,并且其类型为Object,这样就支持实际的ContentControl(例如,Button)上的如下用法:。
类型必须声明一个类型转换器,该类型转换器将文本内容用作其初始化文本。例如,
类型必须为已知的 XAML 语言基元。
内容属性和集合语法组合
请看以下示例:
XAML
此例中,每个Button都是StackPanel的一个子元素。这是一个简单直观的标记,其中出于两个不同的原因省略了两个标记。
省略的 en 属性元素:StackPanel从Panel派生。Panel将en定义为其 XAML 内容属性。
省略的 UIElementCollection 对象元素:en属性采用类型UIElementCollection,该类型实现IList。根据处理集合(例如IList)的 XAML 规则,
集合的元素标记可以省略。(在这种情况下,UIElementCollection实际无法实例化,因为它没有公开默认构造函数,这就是UIElementCollection对象元素以注释形式出现的原因。)
XAML
特性语法(事件)
特性语法还可用于事件成员,而不仅限于属性成员。在这种情况下,特性的名称为事件的名称。在 XAML 事件的 WPF 实现中,特性的值是实现该事件的委托的处理程序的名称。例如,以下标记将Click事件的一个处理程序指定给在标记中创建的Button:
XAML
xmlns="/winfx/2006/xaml/presentation" xmlns:x="/winfx/2006/xaml" x:Class="ePage">
除此特性语法示例外,还有更多关于 WPF 中的事件和 XAML 的内容。例如,您可能希望了解此处引用的ClickHandler表示什么,以及它是如何定义的。这将在本主题中后面的一节中解释。
XAML 中的大小写和空白
XAML 通常区分大小写。出于解析后备类型的目的,WPF XAML 按照 CLR 区分大小写的相同规则区分大小写。按名称与程序集中的基础类型进行比较或者与类型的成员进行比较时,对象元素、属性元素和特性名称均必须使用区分大小写的形式指定。 XAML 语言关键字和基元也区分大小写。值并不总是区分大小写。值是否区分大小写将取决于与采用该值的属性关联的类型转换器行为,或取决于属性值类型。例如,采用Boolean类型的属性可以采用true或True作为等效值,但只是因为将字符串转换为Boolean的本机 WPF XAML 分析器类型转换已经允许将这些值作为等效值。
WPF XAML 处理器和序列化程序将忽略或删除所有无意义的空白,并规范化任何有意义的空白。这与 XAML 规范的默认空白行为建议一致。通常,只有当您在 XAML 内容属性中指定字符串时,此行为的重要性才会体现出来。简言之,XAML 将空格、换行符和制表符转化为空格,如果它们出现在一个连续字符串的任一端,则保留一个空格。有关XAML 空白处理的完整说明不属于本主题的讨论范围。有关详细信息,请参见XAML 中的空白处理。
标记扩展
标记扩展是一个 XAML 语言概念。当用于提供特性语法的值时,大括号({和})表示标记扩展用法。此用法指示 XAML 处理系统不要像通常那样将特性值视为一个文本字符串或者可转换为字符串的值。
WPF 应用程序编程中最常用的标记扩展是Binding(用于数据绑定表达式)以及资源引用StaticResource和DynamicResource。通过使用标记扩展,即使属性通常不支持特性语法,也可以使用特性语法为属性提供值。标记扩展经常使用中间表达式类型实现一些功能,例如,推迟值或引用仅在运行时才存在的其他对象。
例如,下面的标记使用特性语法设置Style属性的值。Style属性采用了Style类的一个实例,该实例默认情况下未能用特性语法字符串实例化。但在本例中,特性引用了特定的标记扩展StaticResource。当处理该标记扩展时,它返回对以前在资源字典中作为键控资源进行实例化的某个样式的引用。
XAML
...
...
有关特定在 WPF 中实现的所有 XAML 标记扩展的参考列表,请参见WPF XAML 扩展。有关由 定义并且可更广泛用于 .NET Framework XAML 实现的标记扩展的参考列表,请参见XAML 命名空间 (x:) 语言功能。有关标记扩展概念的更多信息,请参见标记扩展和 WPF XAML。
类型转换器
在一节中,曾提到特性值必须能够使用字符串进行设置。对字符串如何转换为其他对象类型或基元值的基本本机处理取决于String类型本身,以及对某些类型(如DateTime或Uri)的
本机处理。但是很多 WPF 类型或这些类型的成员扩展了基本字符串特性处理行为,因此可以指定更复杂的对象类型的实例作为字符串和特性。
Thickness结构是一个类型示例,该类型拥有可使用 XAML 的类型转换。Thickness指示嵌套矩形中的度量并用作一些属性(如Margin)的值。通过对Thickness设置类型转换器,所有使用Thickness的属性都可以更容易地在 XAML 中指定,因为它们可指定为特性。下面的示例使用类型转换和特性语法来为Margin提供值:
XAML
上面的特性语法示例与下面更为详细的语法示例等效,但在下面的示例中,Margin改为通过包含Thickness对象元素的属性元素语法进行设置。而且设置Thickness的四个关键属性作为新实例的特性:
XAML
<>
>
说明
还有少数对象只能通过类型转换这种公开方式在不涉及到子类的情况下为该类型设置属性,因为类型本身并没有默认构造函数。一个示例是Cursor。
有关如何支持类型转换及其在特性语法上的应用的更多信息,请参见TypeConverters 和
XAML。
XAML 根元素和 XAML 命名空间
一个 XAML 文件只能有一个根元素,这样才能同时成为格式正确的 XML 文件和有效的
XAML 文件。对于典型的 WPF 方案,将使用在 WPF 应用程序模型中具有重要意义的根元素(例如,为页使用Window或Page,为外部字典使用ResourceDictionary或为应用程序定义使用Application)。下面的示例演示 WPF 页的典型 XAML 文件的根元素,此根元素为Page。
XAML
xmlns="/winfx/2006/xaml/presentation" xmlns:x="/winfx/2006/xaml" ...
根元素还包含特性xmlns和xmlns:x。这些特性向 XAML 处理器指明哪些 XAML 命名空间包含标记将要作为元素引用的后备类型的类型定义。xmlns特性明确指示默认的 XAML
命名空间。在默认的 XAML 命名空间中,可以不使用前缀指定标记中的对象元素。对于大多数 WPF 应用程序方案以及 SDK 的 WPF 部分中给出的几乎所有示例,默认的 XAML
命名空间均映射到为 WPF 命名空间
/winfx/2006/xaml/presentation。xmlns:x特性指示另外一个
XAML 命名空间,该命名空间映射 XAML 语言命名空间
/winfx/2006/xaml。
使用xmlns定义用法范围和名称范围映射的做法符合 XML 1.0 规范。 XAML 名称范围与
XML 名称范围的不同仅在于:XAML 名称范围还包含有关进行类型解析和分析 XAML
时名称范围的元素如何受类型支持的信息。
请注意,只有在每个 XAML 文件的根元素上,xmlns特性才是绝对必需的。xmlns定义将适用于根元素的所有子代元素(此行为也符合xmlns的 XML 1.0 规范)。同时允许根以下的其他元素上具有xmlns特性,这些特性将适用于定义元素的任何子代元素。但是,频繁定义或重新定义 XAML 命名空间可能会导致 XAML 标记样式难以阅读。
其 XAML 处理器的 WPF 实现包括可识别 WPF 核心程序集的基础结构。已知 WPF 核心程序集包含支持 WPF 到默认 XAML 命名空间的映射的类型。这是通过属于项目生成文件以及 WPF 生成和项目系统一部分的配置来实现的。因此,为了引用来自 WPF 程序集的 XAML 元素,只需将默认 XAML 命名空间声明为默认 xmlns。
x: 前缀
在上面的根元素示例中,前缀x:用于映射 XAML 命名空间
/winfx/2006/xaml,该命名空间是支持 XAML 语言构造的专用
XAML 命名空间。在这整个 SDK 的项目模板、示例以及文档中,此x:前缀用于映射该
XAML 命名空间。 XAML 语言的 XAML 命名空间包含多个将在 XAML 中频繁用到的编程构造。下面列出了将用到的最常见的x:前缀编程构造:
x:Key:为ResourceDictionary(或其他框架中的类似字典概念)中的每个资源设置唯一的键。在典型的 WPF 应用程序标记中的所有x:用法中,x:Key将可能占到 90%。
x:Class:向为 XAML 页提供代码隐藏的类指定 CLR 命名空间和类名。必须具有这样一个类才能支持每个 WPF 编程模型的代码隐藏,而正是因此,即使没有资源,也几乎总是能看到映射的x:。
x:Name:处理对象元素后,为运行时代码中存在的实例指定运行时对象名称。通常,您将为x:Name经常使用 WPF 定义的等效属性。此类属性特定映射到 CLR 后备属性,因此更便于进行应用程序编程,在应用程序编程中,您经常使用运行时代码从初始化的
XAML 中查找命名元素。最常见的此类属性是。在特定类型中不支持等效的 WPF 框架级Name属性时,仍然可以使用x:Name。某些动画方案中会发生这种情况。
x:Static:启用一个返回静态值的引用,该静态值只能是一个 XAML 兼容属性。
x:Type:根据类型名称构造一个Type引用。它用于指定采用Type(例如Type)的特性,但属性经常具有本机的字符串到Type的转换功能,因此使用x:Type标记扩展用法是可选的。
x:前缀/XAML 命名空间中还有其他一些不太常见的编程构造。有关详细信息,请参见XAML 命名空间 (x:) 语言功能。
XAML 中的自定义前缀和自定义类型
对于您自己的自定义程序集或 PresentationCore、PresentationFramework 和 WindowsBase
的 WPF 核心以外的程序集,可以将该程序集指定为自定义xmlns映射的一部分。只要该类型能够正确地实现以支持您所尝试的 XAML 用法,就可以在 XAML 中引用该程序集中的类型。
下面是一个说明自定义前缀如何在 XAML 标记中工作的基本示例。前缀custom在根元素标记中定义,并映射为随应用程序一同打包并可用于该应用程序的一个特定程序集。此程序集包含NumericUpDown类型,实现该类型的目的是在支持常规 XAML 用法之外,还可以使用允许在 WPF XAML 内容模型的此特定点执行插入的类继承。通过使用该前缀,此NumericUpDown控件的一个实例声明为对象元素,以便 XAML 分析器可找到包含该类型的 XAML 命名空间,从而找到包含该类型定义的后备程序集的位置。
xmlns="/winfx/2006/xaml/presentation" xmlns:x="/winfx/2006/xaml" xmlns:custom="clr-namespace:NumericUpDownCustomControl;assembly=CustomLibrary" > Height="60"/> ...
有关 XAML 中自定义类型的更多信息,请参见XAML 及 WPF 的自定义类。
有关 XML 命名空间与程序集中后备代码的命名空间如何相关的更多信息,请参见WPF
XAML 的 XAML 命名空间和命名空间映射。
事件和 XAML 代码隐藏
大多数 WPF 应用程序既包括 XAML 标记,也包括代码隐藏。在一个项目中,XAML 编写为.xaml文件,而 CLR 语言(如 Microsoft Visual Basic 或 C#)用于编写代码隐藏文件。在 WPF 编程和应用程序模型中对 XAML 文件进行标记编译时,XAML 文件的 XAML
代码隐藏文件的位置是通过如下方式来标识的:以 XAML 的根元素的x:Class特性形式指定一个命名空间和类。
在目前已介绍的示例中,您已看到几个按钮,但还没有一个按钮具有任何关联的逻辑行为。为对象元素添加行为的主要应用程序级机制是使用元素类的现有事件,并为在运行时引发该事件时调用的该事件编写特定的处理程序。事件名称以及要使用的处理程序的名称在标记中指定,而实现处理程序的代码在代码隐藏中定义。
XAML
xmlns="/winfx/2006/xaml/presentation" xmlns:x="/winfx/2006/xaml" x:Class="ePage">
VB
PrivateSub Button_Click(ByVal sender As , ByVal e As
EventArgs)
Dim b As Button =
ound =
EndSub
C#
namespace ExampleNamespace
{
publicpartialclass ExamplePage
{
void Button_Click(object sender, RoutedEventArgs e)
{
Button b = as Button;
ound = ;
}
}
}
请注意,代码隐藏文件使用 CLR 命名空间ExampleNamespace并将ExamplePage声明为该命名空间内的一个分部类。这相当于在标记根中提供的ePage的x:Class特性值。 WPF 标记编译器将通过从根元素类型派生一个类,为编译的任何 XAML
文件创建一个分部类。当您提供也会定义同一分部类的代码隐藏时,将在与编译的应用程序相同的命名空间和类中组合生成的代码。
有关 WPF 中代码隐藏编程要求的更多信息,请参见WPF 中的代码隐藏和 XAML中的“代码隐藏、事件处理程序和分部类要求”一节。
如果您不想创建一个单独的代码隐藏文件,还可以将代码内联到 XAML 文件中。但是,内联代码是一种缺少多样性的方法,有很多的限制。有关详细信息,请参见WPF 中的代码隐藏和 XAML。
路由事件
路由事件是一个特殊的事件功能,该功能是 WPF 的基础。路由事件使一个元素可以处理另一个元素引发的事件,前提是这些元素通过树关系连接在一起。使用 XAML 特性指定事件处理时,可以对任何元素(包括未在类成员表中列出路由事件的元素)侦听和处理该路由事件。这是通过以所属类名限定事件名特性来实现的。例如,在当前所讨论的StackPanel /
Button示例中,父StackPanel可以通过在StackPanel对象元素上指定特性,并使用处理程序名作为特性值,为子元素按钮的Click事件注册一个处理程序。有关路由事件如何工作的更多信息,请参见路由事件概述。
XAML 命名元素
默认情况下,通过处理 XAML 对象元素在对象图中创建的对象实例没有唯一标识符或对象引用。相反,如果在代码中调用构造函数,则几乎总是使用构造函数结果为构造的实例设置一个变量,以便以后在代码中引用该实例。为了对通过标记定义创建的对象提供标准化访问,XAML 定义了x:Name 特性。您可以在任何对象元素上设置x:Name特性的值。在代码隐藏中,您选择的标识符等效于引用所构造的实例的实例变量。在任何方面,命名元素都像它们是对象实例一样工作(此名称引用该实例),并且代码隐藏可以引用该命名元素来处理应用程序内的运行时交互。实例和变量之间的这种连接是由 WPF XAML 标记编译器实现的,并且更具体涉及到功能和模式,例如本主题中将不详细讨论的InitializeComponent。
WPF 框架级 XAML 元素继承Name属性,该属性等效于 XAML 定义的x:Name特性。其他某些类也为x:Name(通常也定义为Name属性)提供属性级等效项。一般而言,如果您在所选元素/类型的成员表中找不到Name属性,则可以改用x:Name。x:Name值将通过特定子系统或通过诸如FindName等实用工具方法,为可在运行时使用的 XAML 元素提供标识符。
下面的示例在StackPanel元素上设置Name。然后,该StackPanel中的Button上的处理程序通过由Name设置的实例引用buttonContainer来引用StackPanel。
XAML
...
VB
PrivateSubRemoveThis(ByVal sender As , ByVal e As
EventArgs)
DimfeAs FrameworkElement =
If (ns(fe)) Then
(fe)
EndIfEndSub
C#
void RemoveThis(object sender, RoutedEventArgs e)
{
FrameworkElement fe = as FrameworkElement;
if (ns(fe))
{
(fe);
}
}
就像变量一样,实例的 XAML 名称受范围概念的控制,因此可以在可预测的某个范围内强制名称唯一。定义页面的主标记表示一个唯一的 XAML 名称范围,而该 XAML 名称范围的边界就是该页面的根元素。但是,其他标记源(如样式或样式中的模板)可以在运行时与页面交互,这种标记源常常具有自己的 XAML 名称范围,这些名称范围不一定与页面的
XAML 名称范围相关联。有关x:Name和 XAML 名称范围的更多信息,请参见Name、x:Name 指令或WPF XAML 名称范围。
附加属性和附加事件
XAML 指定了一个语言功能,该功能允许对任何元素指定某些属性或事件,而不管要设置属性或事件的元素的类型定义中是否存在该属性或事件。该功能的属性版本称为附加属性,事件版本称为附加事件。从概念上讲,可以将附加属性和附加事件视为可以在任何 XAML
元素/对象实例上设置的全局成员。但是,元素/类或更大的基础结构必须支持附加值的后备属性存储。
通常通过特性语法来使用 XAML 中的附加属性。在特性语法中,您可以采用“所有者类型.属性名”的形式指定附加属性。
表面上,这与属性元素用法类似,但在这种情况下,您指定的“所有者类型”始终是一种与从中要设置附加属性的对象元素不同的类型。 “所有者类型”这种类型提供 XAML 处理器为获取或设置附加属性值所需要的访问器方法。
使用附加属性的最常见方案是使子元素能够向其父元素报告属性值。
下面的示例演示了附加属性。DockPanel类为定义访问器,因此拥有附加属性。DockPanel类还包括一个逻辑,该逻辑迭代其子元素并具体检查每个元素是否具有设置值。如果找到一个值,将在布局过程中使用该值定位子元素。使用附加属性和这种定位功能事实上是DockPanel类的激动人心的一面。
XAML
<="Left"Width="100"Height="20">I am on the
left
<="Right"Width="100"Height="20">I am on the
right
在 WPF 中,大部分或所有附加属性还作为依赖项属性来实现。有关详细信息,请参见附加属性概述。
附加事件使用类似的“所有者类型.事件名”特性语法形式。就像非附加事件一样,XAML 中的附加事件的特性值指定对元素处理事件时调用的处理程序方法的名称。在 WPF XAML
中使用附加事件并不常见。有关更多信息,请参见附加事件概述。
基类型和 XAML
基础 WPF XAML 及其 XAML 命名空间是类型的一个集合,这些类型对应于 CLR 对象以及 XAML 的标记元素。但是,并不是所有的类都能映射到元素。抽象类(如ButtonBase)和某些非抽象基类在 CLR 对象模型中用于继承。基类(包括抽象类)对于 XAML 开发仍然很重要,因为每个具体的 XAML 元素都从其层次结构中的某个基类继承成员。通常,这些成员包括可以设置为元素特性的属性或者可以处理的事件。FrameworkElement是 WPF
在 WPF 框架级的具体 UI 基类。设计 UI 时,您将使用各种形状、面板、修饰器或控件类,它们全部从FrameworkElement派生而来。有一个相关的基类FrameworkContentElement,它使用可在FrameworkElement中特意镜像 API 的 API,支持适合流布局表示形式的面向文档的元素。元素级的特性和 CLR 对象模型的组合提供了一组通用的属性,这些属性可以在大多数具体的 XAML 元素上设置,而不管具体的 XAML 元素类型及其基础类型是什么。
XAML 安全性
XAML 是一种直接表示对象实例化和执行的标记语言。因此,在 XAML 中创建的元素能够像等效的生成代码那样与系统资源(如网络访问、文件系统 IO)进行交互。
WPF 支持 .NET Framework 4 安全框架代码访问安全性 (CAS)。这意味着在 Internet 区域中运行的 WPF 内容具有更少的执行权限。" “宽松 XAML”(由 XAML 查看器在加载时解释的非编译 XAML 的页面)和 XAML 浏览器应用程序 (XBAP) 通常在此 Internet 区域中运行,并且使用相同的权限集。但是,加载到完全受信任的应用程序中的 XAML 与承载应用程序具有相同的系统资源访问权限。有关更多信息,请参见WPF 部分信任安全。
从代码中加载 XAML
XAML 可用于定义整个 UI,但有时也适合在 XAML 中定义 UI 的一部分。此功能可用于实现部分自定义,在本地存储信息,使用 XAML 提供业务对象或者各种可能的方案。这些方案的关键是XamlReader类及其Load方法。输入是一个 XAML 文件,而输出是一个对象,表示从该标记创建的整个运行时对象树。然后您可以插入该对象,作为应用程序中已存在的另一个对象的属性。只要该属性在具有最终显示功能并且将通知执行引擎已向应用程序中添加新内容的内容模型中是一个合适的属性,就可以通过载入 XAML 非常轻松地修改正在运行的应用程序的内容。请注意,通常只在完全受信任的应用程序中使用此功能,因为将文件加载到正在运行的应用程序中会带来明显的安全隐患。
接下来的内容
本主题简单介绍了适用于 WPF 的 XAML 语法概念和术语。有关本文使用的术语的更多信息,请参见XAML 语法详述。
如果尚未做过演练:开始使用 WPF教程主题中的练习,请试做。当您创建该教程中介绍的以标记为中心的应用程序时,其中的练习将帮助您巩固本主题中介绍的许多概念。
WPF 使用一个特定的应用程序模型,该模型基于Application类。有关详细信息,请参见应用程序管理概述。
生成 WPF 应用程序 (WPF)为您详细介绍了如何通过命令行以及使用 Microsoft Visual
Studio 生成包含 XAML 的应用程序。
依赖项属性概述详细介绍了 WPF 中属性的多样性,并介绍了依赖项属性的概念。
XAML 语法详述
本主题定义用于描述 XAML 语法中各个元素的术语。 本文档的其余部分将经常用到这些术语,既特定适用于 WPF 文档,也适用于其他框架,这些框架使用由 级
别的 XAML 语言支持实现的 XAML 或基本 XAML 概念。 本主题进一步阐述主题 XAML
概述 (WPF)中曾介绍过的基本术语。
本主题包括下列各节。
XAML 语言规范
XAML 和 CLR
对象元素语法
对象元素的属性
特性语法(属性)
属性元素语法
集合语法
XAML 内容属性
内容属性和集合语法组合
XAML 命名空间
标记扩展
附加属性
附加事件
XAML 根元素剖析
可选的和不建议的 XAML 用法
相关主题
XAML 语言规范
XAML 语言规范中也定义或引用了此处定义的 XAML 语法术语。 XAML 是一种基于
XML 并遵循或扩展 XML 结构规则的语言。 其中某些术语共享自或基于描述 XML 语言或 XML 文档对象模型时常用的术语。
有关 XAML 语言规范的更多信息,请从 Microsoft 下载中心下载 [MS-XAML]。
XAML 和 CLR
XAML 是一种标记语言。 顾名思义,公共语言运行时 (CLR) 实现了运行时执行。 XAML 本身并非 CLR 运行时直接使用的一种公共语言。 而是可以将 XAML 视为支持其自身的类型系统。 WPF 所使用的特定 XAML 分析系统是根据 CLR 和 CLR 类型系统构建的。 在分析 WPF 的 XAML 时,XAML 类型将映射到 CLR 类型,以便将运行时表示形式实例化。 出于此原因,本文档中语法讨论的其余部分将包括对 CLR 类型系统的引用,而 XAML
语言规范中并未就这部分语法展开讨论。 (在 XAML 语言规范的每个级别,XAML 类型都可以映射到任何其他类型系统,而不一定要映射到 CLR,但这需要创建和使用一种不同的 XAML 分析器。)
类型成员和类继承
属性和事件在作为 WPF 类型的 XAML 成员时,通常从基类型继承而来。 请考虑此代码示例:。 如果要查看类定义、反射结果或文档,则 Background 属性并不是 Button 类上立即声明的属性。 相反,Background 是从基 Control 类继承而来。
WPF XAML 元素的类继承行为与架构对 XML 标记的强制解释大相径庭。 类继承可能会变得很复杂,特别是在中间基类为抽象类或涉及到接口的情况下尤为如此。 由于这样一个原因,因此很难通过 XML 编程常用的架构类型(例如 DTD 或 XSD 格式)准确并完整
地表示 XAML 元素及其所允许特性的集合。 另一个原因是,XAML 语言本身的扩展性和类型映射功能会对所允许类型和成员的任何固定表示形式的完整性造成妨碍。
对象元素语法
对象元素语法是一种 XAML 标记语法,它通过声明 XML 元素将 CLR 类或结构实例化。 这种语法类似于如 HTML 等其他标记语言的元素语法。 对象元素语法以左尖括号 (<)
开始,后面紧跟要实例化的类或结构的类型名称。 类型名称后面可以有零个或多个空格,对于对象元素还可以声明零个或多个特性,并用一个或多个空格来分隔每个“特性名="值"”对。 最后,必须存在下列一种情况:
元素和标记必须用正斜杠 (/) 和紧跟的右尖括号 (>) 结尾。
开始标记必须以右尖括号 (>) 结尾。 其他对象元素、属性元素或内部文本可以跟在开始标记后面。 此处可以包含的确切内容通常会受到元素对象模型的约束。对象元素还必须存在等效的结束标记,并与其他开始标记/结束标记对形成正确的嵌套和平衡。
由 .NET 实现的 XAML 具有一组规则,可将对象元素映射为类型、将特性映射为属性或事件,以及将 XAML 命名空间映射到 CLR 命名空间和程序集。 对于 WPF 和 .NET
Framework,XAML 对象元素映射到 Microsoft .NET 类型(如引用的程序集中所定义),而特性映射到这些类型的成员。 在 XAML 中引用 CLR 类型时,还可以访问该类型的继承成员。
例如,下面的示例是一个对象元素语法,该语法实例化 Button 类的一个新实例,而且还指定了一个 Name 特性及其值:
XAML
下例是其中也包括 XAML 内容属性语法的对象元素语法。 其中包含的内部文本将用于设置 TextBox 的 XAML 内容属性 Text。
XAML
内容模型
从语法上讲,类可能支持作为 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 分析器进行内部处理,而枚举的成员则应该通过指定枚举的某个命名常量的字符串名称进行指定。
对于无标志的枚举值,本机行为是处理特性值的字符串并将它解析为某个枚举值。 您不必像在代码中那样指定格式为枚举.值 的枚举, 而是仅指定值,枚举 将从所设置属性的类型推断。 如果您指定格式为枚举.值 的特性,它将无法正确解析。
对于按标志枚举,该行为基于 方法。 您可以通过用逗号分隔每个值来为按标志枚举指定多个值。 但是,您不能合并不按标志的枚举值。 例如,不能尝试使用逗号语法来创建作用于无标志枚举多个条件的 Trigger:
...
...
在 WPF 中,很少有按标志枚举能支持可在 XAML 中设置的特性。 但是,StyleSimulations 就是这样的一个枚举。 例如,可以使用逗号分隔的按标志特性语法修改在Glyphs 类的“Remarks”(备注)部分中提供的示例;StyleSimulations =
"BoldSimulation" 可以变为 StyleSimulations = "BoldSimulation,ItalicSimulation"。ers 是另一个其中可指定多个枚举值的属性。 但是,此属性恰好是一个特例,因为 ModifierKeys 枚举支持其自身的类型转换器。 修饰符的类型转换器使用加号
(+) 而不是逗号 (,) 作为分隔符。 此转换支持用更传统的语法表示 Microsoft Windows
编程中的组合键(如“Ctrl+Alt”)。
属性引用和事件成员名称引用
指定特性时,可以引用作为您为包含对象元素实例化的 CLR 类型的成员而存在的任何属性或事件。
或者,可以独立于包含对象元素来引用附加属性或附加事件。 (后面的某节即将讨论附加属性。)
对于可通过默认命名空间访问的任何对象中的任何事件,还可以通过使用“类型名称.事件”部分限定名来命名;此语法支持为路由事件附加处理程序,在路由事件中,处理程序旨在处理子元素中的事件路由,但是父元素在其成员表中并不拥有该事件。 此语法与附加事件语法相似,但此处的事件不是真正的附加事件。 相反,您引用的是具有限定名称的事件。 有关更多信息,请参见路由事件概述。
对于某些情况,属性名称有时是以特性的值(而不是特性名称)的形式提供的。 该属性名称还可以包括限定符,例如以所有者类型.依赖项属性名称 格式指定的属性。在 XAML 中
编写样式或模板时,此情况较为常见。 以特性值形式提供的属性名称具有不同的处理规则,这些规则由所设置的属性类型或特定 WPF 子系统的行为控制。有关详细信息,请参见样式设置和模板化。
当特性值描述属性之间的关系时,也可以使用属性名。 此功能可用于数据绑定和演示图板目标,而且由 PropertyPath 类及其类型转换器启用。 有关查找语义的更完整说明,请参见 PropertyPath XAML 语法。
属性元素语法
属性元素语法是一种与元素的基本 XML 语法规则略有不同的语法。 在 XML 中,特性的值实际上是一个字符串,唯一可能的变化是使用哪种字符串编码格式。 在 XAML 中,可以指定其他对象元素作为属性的值。 此功能由属性元素语法来启用。 并不将属性指定为元素标记内的特性,而是使用元素的开始标记指定“元素类型名称.属性名称”形式的属性,在其中指定属性的值,然后结束属性元素。
具体而言,该语法以左尖括号 (<) 开头,其后紧跟包含属性元素语法的类或结构的类型名称。 类型名称后面紧跟一个点 (.),然后跟属性的名称,最后跟一个右尖括号 (>)。 对于特性语法,指定类型的已声明公共成员内必须存在该属性。 要赋给属性的值包含在相应的属性元素中。 通常,值作为一个或多个对象元素提供,因为将对象指定为值正是属性元素语法应当实现的方案。 最后,必须提供一个等效的结束标记来指定同一个元素类型名称.属性名称 组合,并与其他元素标记对形成正确的嵌套和平衡。
例如,下面的属性元素语法针对的是 Button 的 ContextMenu 属性。
XAML
Right-click me!
当要指定的属性类型是基元值类型(如 String)或是指定了名称的枚举时,也可以用内部文本的形式给出属性元素中的值。 这两个用法在某种程度上并不常见,因为这两种情况都还可以使用更简单的特性语法。 用字符串填充属性元素的一个方案是,对于不是 XAML 内容属性但仍用于表示 UI 文本的属性,该 UI 文本中必须出现特定的空白元素(如换行符)。 特性语法不能保留换行符,但是属性元素语法可以保留换行符,不过前提是用来保留大量空白的功能处于活动状态(有关详细信息,请参见XAML 中的空白处理)。 另一个方案使 x:Uid 指令可应用于属性元素,并因此将其中的值标记为应在 WPF 输出 BAML
中本地化或通过其他技术本地化的值。
属性元素不以 WPF 逻辑树的形式表示。 属性元素不是由实例或对象支持的元素,而只是一个用来设置属性的特定语法。 (有关逻辑树概念的详细信息,请参见 WPF 中的树。)
对于同时支持特性语法和属性元素语法的属性,尽管这两种语法的细微之处(如空白处理)略有不同,但它们的结果通常是一样的。
集合语法
XAML 规范要求 XAML 处理器实现能标识其中值类型为集合的属性。 .NET 中的常规
XAML 处理器实现基于托管代码和 CLR,并且该处理器实现通过以下各项之一标识集合类型:
类型实现 IList。
类型实现 IDictionary。
类型从 Array 派生(有关 XAML 中数组的更多信息,请参见 x:Array 标记扩展)。
如果属性的类型是集合,则不必在标记中以对象元素的形式指定推断的集合类型。 而要成为集合中项的元素将被指定为属性元素的一个或多个子元素。 在加载每个此类项的过程中会将该项计算为对象,然后通过调用隐含集合的 Add 方法将其添加到集合中。 例如,Style 的 Triggers 属性采用专用的集合类型 TriggerCollection(该类型实现 IList)。 不必在标记中将 TriggerCollection 对象元素实例化。 而是需要在 rs 属性元素中指定一个或多个 Trigger 项作为元素,其中 Trigger(或派生类)是一个类型,应当作为隐式强类型 TriggerCollection 的项类型。
XAML
属性可以既是一个集合类型,又是该类型和派生类型的 XAML 内容属性,本主题的下一节将讨论这种情况。
隐式集合元素在逻辑树表示形式中创建一个成员,即使该成员不以元素的形式出现在标记中也是如此。 通常,父类型的构造函数对作为其属性之一的集合执行实例化,然后最初为空的集合将成为对象树的一部分。
说明
集合检测功能不支持泛型列表和字典接口(IList TValue> 用作基类(因为它直接实现 IDictionary)。 在集合类型的 .NET 参考页中,这种特意省略集合的对象元素的语法在 XAML 语法部分中有时称为“隐式集合语法”。 除了根元素外,XAML 文件中以另一个元素的子元素形式嵌套的每个对象元素实际上都属于下列一种或两种情况:父元素的隐式集合属性的成员,或是为父元素指定 XAML 内容属性值的元素(后面的某节即将讨论 XAML 内容属性)。 换言之,一个标记页上的父元素与子元素之间的关系实际上就是一个根对象,而根对象下面的每个对象元素要么是为父元素 提供属性值的一个实例,要么是同样作为父元素的集合类型属性值的集合中的一项。 这种单根概念对于 XML 很常见,并且经常在加载 XAML 的 API(例如 Load)的行为中得到加强。 下例是一种显式指定集合 (GradientStopCollection) 的对象元素的语法。 XAML 请注意,并不总是能够显式声明集合。 例如,尝试在前面演示过的 Triggers 示例中显式声明 TriggerCollection 就会失败。 显式声明集合要求集合类必须支持默认构造函数,而 TriggerCollection 没有默认构造函数。 XAML 内容属性 XAML 内容语法作为一种语法,仅在指定 ContentPropertyAttribute 作为其类声明一部分的类上启用。 ContentPropertyAttribute 引用作为该类型元素(包括派生类)的内容属性的内容名称。 当 XAML 处理器处理在对象元素的开始标记和结束标记之间找到的任何子元素或内部文本时,会向其赋予该对象的 XAML 内容属性的值。 对于内容属性允许指定显式的属性元素,但 .NET 参考的 XAML 语法章节中一般不介绍这种用法。 这种显式/ 详细的方法有时很实用,可使标记清晰明确或作为一种重要的标记样式,但内容属性的意图通常是要简化标记,以便可以直接嵌套直观相关的父/子元素。 对于元素上其他属性的属性元素标记,并不按严格的 XAML 语言定义将其指派为“内容”;这些标记以前是按 XAML 分析器的处理顺序进行处理的,并不将其视为“内容”。 XAML 内容属性值必须连续 XAML 内容属性的值必须完全在该对象元素的其他任何属性元素之前或之后指定。 无论将 XAML 内容属性的值指定为字符串还是指定为一个或多个对象都是如此。 例如,无法分析以下标记: blue button 这在本质上是非法的,因为如果此语法是通过使用内容属性的属性元素语法而变为显式的,则内容属性将设置两次: 一个类似的非法示例是,如果内容属性是一个集合,则子元素是与属性元素交错的: 内容属性和集合语法组合 为了接受多个对象元素作为内容,内容属性的类型必须明确地是集合类型。 与集合类型的属性元素语法相似,XAML 处理器必须标识作为集合类型的类型。 如果某个元素具有 XAML 内容属性,并且该 XAML 内容属性的类型为集合,则不需要在标记中指定隐含的集合类型作为对象元素,也不需要指定该 XAML 内容属性作为属性元素。 因此,标记中明显的内容模型现在可以将多个子元素作为指定为内容。 下面是 Panel 派生类的内容语法。 所有 Panel 派生类都证实 XAML 内容属性为Children(它要求值为 UIElementCollection 类型)。 XAML xmlns="/winfx/2006/xaml/presentation" xmlns:x="/winfx/2006/xaml" > 请注意,标记中既不需要 Children 的属性元素也不需要 UIElementCollection 的元素。 这是 XAML 的特有设计,其目的是为了让用于定义 UI 的递归包含元素按紧邻的父-子元素关系更直观地表示为嵌套元素的树,而不必干预属性元素标记或集合对象。 实际上,特意 使 UIElementCollection 不能在标记中被显式指定为对象元素。由于 UIElementCollection 唯一的用途就是作为隐式集合,因此它不公开公共的默认构造函数,因此不能实例化为对象元素。 在具有内容属性的对象中混合使用属性元素和对象元素 XAML 规范声明 XAML 处理器可以强制用于填充某个对象元素中 XAML 内容属性的各个对象元素必须连续,并且不得混合使用。 针对混合使用属性元素和内容的这一限制由 WPF XAML 处理器强制实施。 可以将子对象元素作为某个对象元素中的第一个直接标记, 然后可以引入属性元素。 也可以指定一个或多个属性元素,接着指定内容,然后指定多个属性元素。 但是,一旦内容后面跟有属性元素,您就不能进一步引入任何内容,而只能添加属性元素。 这个内容/属性元素顺序要求不适用于用作内容的内部文本。 然而,这仍然是使内部文本保持连续的不错的标记样式,原因是,如果属性元素与内部文本交错分布,则很难直观地检测标记中的大量空白。 XAML 命名空间 上述所有语法示例均未指定默认 XAML 命名空间以外的 XAML 命名空间。 在典型的 WPF 应用程序中,将默认 XAML 命名空间指定为 WPF 命名空间。 您可以指定默认 XAML 命名空间以外的其他 XAML 命名空间,并仍然使用类似的语法。 但是,只要无法在默认 XAML 命名空间中访问已命名的类,就必须在该类名称之前加上映射到对应 CLR 命名空间的 XAML 命名空间的前缀。 例如, 有关 XAML 命名空间的更多信息,请参见 WPF XAML 的 XAML 命名空间和命名空间映射。 标记扩展 XAML 定义了一个标记扩展编程实体,该实体允许从 XAML 处理器对字符串特性值或对象元素的常规处理中进行转义,并将处理转交给后备类。 在使用特性语法时,标识 XAML 处理器的标记扩展的字符是左大括号 ({),后接右大括号 (}) 以外的任何字符。 左大括号后面的第一个字符串必须引用用来提供特定扩展行为的类,如果子字符串“Extension”是实际类名的一部分,则该引用可以省略这个子字符串。 该类后面可能会出现一个空格,该空格后面的每个字符都可以由所实现的扩展用作输入,直到遇到右大括号。 .NET XAML 实现使用 MarkupExtension 抽象类作为 WPF 以及所有其他框架或技术支持的所有标记扩展的基础。 WPF 特定实现的标记扩展通常用于提供一种方法来引用其他已经存在的对象,或者对将在运行时计算的对象进行延迟引用。 例如,通过指定用 {Binding} 标记扩展代替特定属性通常将采用的值,从而实现简单的 WPF 数据绑定。 对于无法以其他方式使用特性语法的属性,许多 WPF 标记扩展都允许使用特性语法。 例如,Style 对象是一种相对复杂的类型,其中包含一系列嵌套的对象和属性。 WPF 中的样式通常定义为 ResourceDictionary 中的资源,之后将通过请求资源的两个 WPF 标记扩展之一来引用。 标记扩展将属性值的计算推迟到查找资源时进行,并允许在特性语法中提供 Style 属性的值并采用 Style 类型,如下例所示: 在这里,StaticResource 用来标识 StaticResourceExtension 类,该类提供标记扩展实现。 下一个字符串 MyStyle 用作非默认 StaticResourceExtension 构造函数的输入,在该 构造函数中,从扩展字符串提取的参数将声明所请求的 ResourceKey。 MyStyle 应当是定义为资源的 Style 的 x:Key 值。 StaticResource 标记扩展 用法要求使用该资源,在加载时通过静态资源查找逻辑来提供 Style 属性值。 有关标记扩展的更多信息,请参见标记扩展和 WPF XAML。 有关常规 .NET XAML 实现中启用的标记扩展和其他 XAML 编程功能的参考,请参见 XAML 命名空间 (x:) 语言功能。 有关特定于 WPF 的标记扩展,请参见 WPF XAML 扩展。 附加属性 附加属性是 XAML 中引入的一个编程概念,借此,特定类型可以拥有和定义属性,但在任何元素上都将属性设置为特性或属性元素。 附加属性所面向的主要方案是,允许标记结构中的子元素向父元素报告信息,同时不需要在所有元素之间广泛共享的对象模型。 相反,附加属性可以由任何父元素用来向子元素报告信息。 有关附加属性的用途以及如何创建您自己的附加属性的更多信息,请参见附加属性概述。 附加属性使用的语法在表面上与属性元素语法非常相似,因为您还需要指定类型名.属性名 组合。 二者有两个重要的差异: 即使在通过特性语法设置附加属性时,也可以使用类型名.属性名 组合。 只有附加属性才要求特性语法中使用限定属性名。 对于附加属性还可以使用属性元素语法。 但是,对于典型的属性元素语法,您指定的类型名 是包含属性元素的对象元素。 如果您引用的是附加属性,则类型名是用来定义附加属性的类,而不是包含对象元素。 附加事件 附加事件是 XAML 中引入的另一个编程概念,其中可以由特定类型定义事件,但处理程序可以附加到任何对象元素上。 在 WPF 实现中,用于定义附加事件的类型通常是用于定义服务的静态类型,而这些附加事件有时由用于公开服务的类型中的路由事件别名公开。 附加事件的处理程序是通过特性语法指定的。 就附加事件而言,特性语法针对附加事件进行了扩展,以便允许“类型名称.事件名称”用法,其中“类型名称”是为附加事件基础结构提供 Add 和 Remove 事件处理程序访问器的类,而“事件名称”是事件名称。 XAML 根元素剖析 下表显示了一个经过分解的典型 XAML 根元素,同时显示了根元素的具体特性: xmlns="/winfx/2006/xaml/presentation" 默认 (WPF) XAML 命名空间 xmlns:x="/winfx/2006/xaml" XAML 语言 XAML 命名空间 x:Class="eCode" 分部类声明,它将标记连接到为分部类定义的任何代码隐藏 > 根的对象元素的末尾。 由于该元素包含子元素,因此对象未结束 可选的和不建议的 XAML 用法 以下各节描述 XAML 处理器在技术上支持的 XAML 用法,但这些用法会产生冗长的内容或其他美观上的问题,当您开发包含 XAML 源的应用程序时,这些问题会对保持可读的 XAML 文件产生影响。 属性元素的可选用法 属性元素的可选用法包括,显式写入被 XAML 处理器视为隐式的元素内容属性。 例如,声明 Menu 的内容时,可以选择将 Menu 的 Items 集合显式声明为<> 属性元素标记,并将每个 MenuItem 放置在 <> 中,而不是使用隐式 XAML 处理器行为(即,Menu 的所有子元素都必须是 MenuItem而且放置在 Items 集合中)。 有时,这个可选用法可以帮助以可视方式阐明标记中所表示的对象结构。 或者,属性元素的隐式用法有时可以避免使用在技术上具有功能,但在视觉上容易引起混淆(如在特性值中嵌套标记扩展)的标记。 Name 全限定特性 使用特性的类型名称.成员名称 格式实际上比仅仅使用路由事件的情况更为普遍。 但是,在其他情况下,如果只是为了实现标记样式和可读性,则该格式是多余的,您应当避免使用它。 在下面的示例中,对 Background 特性的三个引用是完全等效的: XAML ound 之所以适用,是因为在 Button 上对该属性的限定查找获得成功(Background 从 Control 继承而来),而且 Button 是对象元素的类或者基类。ound 之所以适用,是因为 Control 类实际定义了 Background,而且 Control 是 Button 的基类。 但是,下面的类型名.成员名 格式示例并不适用,因此显示为已注释掉: XAML Label 是 Control 的另一个派生类,而且,如果在 Label 对象元素中指定了 ound,则该用法将适用。 但是,由于 Label 不是 Button 的类或基类,因此指定的 XAML 处理器行为是随后将 ound 作为附加属性进行处理。 ound 不是可用的附加属性,因此这个用法将失败。 Name 属性元素 与“类型名称.成员名称”格式如何适用于特性语法类似,“基类型名称.成员名称”语法适用于属性元素语法。 例如,下面的语法适用: XAML 在这里,即使属性元素包含在 Button 中,属性元素也会以 ound 形式提供。 但是,正如特性的“类型名称.成员名称”形式一样,“基类型.成员名称”在标记中不是良好的样式,应当避免使用这种形式。 WPF 中的代码隐藏和 XAML 代码隐藏是一个术语,用于描述对 XAML 页进行标记编译时与标记定义的对象联接的代码。 本主题描述代码隐藏的要求以及在 XAML 中的代码的可选内联代码机制。 本主题包含以下各节: 必备组件 代码隐藏和 XAML 语言 WPF 中的代码隐藏、事件处理程序和分部类要求 x:Code 内联代码限制 必备组件 本主题假设您已阅读 XAML 概述 (WPF)并已基本了解 CLR 和面向对象的编程。 代码隐藏和 XAML 语言 XAML 语言包括语言级功能,这些功能可以从标记文件端将代码文件与标记文件关联。 具体而言,XAML 语言定义语言功能 x:Class 指令、x:Subclass 指令 和x:ClassModifier 指令。 应如何生成代码以及如何集成标记和代码恰好不属于 XAML 语言指定的内容。 如何集成代码、如何在应用程序和编程模型中使用 XAML 以及如何生成操作或所有这些操作所需的其他支持,都留给框架(例如 WPF)来确定。 WPF 中的代码隐藏、事件处理程序和分部类要求 分部类必须派生自支持根元素的类型。 请注意,在标记编译生成操作的默认行为下,您可以在代码隐藏端的分部类定义中将派生保留为空。 编译的结果将假定页根的支持类型为分部类的基础,即使未指定也是如此。 但是,依赖于此行为并不是最佳做法。 在代码隐藏中编写的事件处理程序必须是实例方法且不能是静态方法。 这些方法必须由 x:Class 标识的 CLR 命名空间中的分部类定义。 您不能限定事件处理程序的名称来指示 XAML 处理器在不同的类范围中查找事件连结的事件处理程序。 处理程序必须与支持类型系统中相应事件的委托匹配。 专门针对 Microsoft Visual Basic 语言,您可以使用特定于语言的 Handles 关键字将处理程序与处理程序声明中的实例和事件关联,而不是在 XAML 中将处理程序附加到特性。 但是,这一技术确实存在一些限制,因为 Handles 关键字不支持 WPF 事件系 统的所有特定功能,例如某些路由事件方案或附加事件。 有关详细信息,请参见 Visual Basic 和 WPF 事件处理。 x:Code x:Code 是在 XAML 中定义的指令元素。x:Code 指令元素可以包含内联编程代码。 内联定义的代码可以与同一页中的 XAML 进行交互。 下面的示例阐释了内联 C# 代码。 请注意,该代码位于 x:Code 元素内,并且必须包围在 XAML xmlns="/winfx/2006/xaml/presentation" xmlns:x="/winfx/2006/xaml" x:Class="asCodeInline" > void Clicked(object sender, RoutedEventArgs e) { t = "Hello World"; } ]]> 内联代码限制 应注意避免或限制使用内联代码。 在体系结构和编码原理方面,保留标记和代码隐藏之间的独立性可以更显著地区分设计人员和开发人员这两个角色。 从更为技术性的角度看,为内联代码编写的代码更难编写,因为您总是要写入到 XAML 生成的分部类中,并且只能使用默认的 XML 命名空间映射。 因为不能添加 using 语句,因此必须完全限定您所进行的大量 API 调用。 默认的 WPF 映射包括在 WPF 程序集中出现的大多数而非全部 CLR 命名空间;您必须完全限定对其他 CLR 命名空间中包含的类型和成员的调用。 此外,您还不能在内联代码中定义超出分部类的任何类,并且引用的所有用户代码实体均必须作为生成的分部类中的一个成员或变量存在。 其他特定于语言的编程功能(例如宏或对全局变量或生成变量的 #ifdef)也不可用。 有关更多信息,请参见 x:Code 内部 XAML 类型。 XAML 及 WPF 的自定义类 使用 XAML 标记, XAML 为已实现在 公共语言运行时 (CLR) framework 支持能够定义自定义类或结构的所有 公共语言运行时 (CLR) 语言,然后访问该类。 您可以在同一标记文件中混合使用 Windows Presentation Foundation (WPF) 定义的类型和您的自定义类型,通常是通过将自定义类型映射到 XAML 命名空间前缀。 本主题讨论自定义类必须满足可用作 XAML 元素的要求。 本主题包括下列各节。 应用程序或程序集中的自定义类 自定义类作为 XAML 元素的要求 自定义类的属性作为 XAML 特性的要求 有关自定义类事件的 XAML 事件处理程序特性语法的要求 编写集合属性 声明 XAML 内容属性 序列化 XAML 相关主题 应用程序或程序集中的自定义类 在 XAML 的自定义类中定义使用两种不同的方法:在代码隐藏或生成主 Windows Presentation Foundation (WPF) 应用程序的其他代码中,或者在单独的程序集中的类后,例如为类库或使用 DLL 的可执行文件。 这些方法中的每一种都有特定的优点和缺点。 创建类库的优点是,任何这样的自定义类都可以在许多可能不同的应用程序中共享。 单独的库也使应用程序的版本问题更易控件,并简化创建预期的类的用法的类,在 XAML 页的根元素。 在应用程序中定义自定义类的优点是,此方法是相对轻型的方法,可最大限度减少当引入主应用程序可执行文件之外的单独程序集时遇到的部署和测试问题。 定义在相同或不同的程序集,自定义类是否需要映射到 CLR 命名空间和 XML 命名空间之间才能用于 XAML 作为元素。 请参见 WPF XAML 的 XAML 命名空间和命名空间映射。 自定义类作为 XAML 元素的要求 类要能够实例化为对象元素,必须满足以下要求: 自定义类必须是公共的且支持默认(无参数)公共构造函数。 (有关结构的说明,请参见以下各节。) 您的自定义类不得是嵌套类。 采用常规 CLR 使用语法的嵌套类和“点”会干扰其他 WPF 和/或 XAML 功能(如附加属性)。 除了启用对象元素语法外,对象定义还为将该对象用作值类型的任何其他公共属性启用属性元素语法。 这是因为,对象现在可以实例化为对象元素,而且可以填充此类属性的属性元素值。 结构 您定义的结构,因为自定义类型始终可以构造在 WPF 的 XAML。这是因为, CLR 编译器隐式创建所有属性值初始化为其默认值的结构的默认构造函数。 在某些情况下,不需要结构的默认构造行为和/或对象元素用法。 这可能是因为该结构在概念上同时用于填充值和函数,其中所含的值可能有互斥的解释,因此其属性都是不可设置的。 这种结构的 WPF 示例有 GridLength。 一般情况下,这种结构应该实现类型转换器,以便可以使用为结构值创建不同解释或模式的字符串约定以特性形式表示值。 该结构还应通过非默认构造函数为代码构造公开类似的行为。 自定义类的属性作为 XAML 特性的要求 属性必须引用按值类型(如基元),或者为具有默认构造函数或 XAML 处理器可以访问的专用类型转换器的类型使用类。 在 CLR XAML 实现中,XAML 处理器可通过对语言基元 的本机支持或通过将 TypeConverterAttribute 应用到后备类型定义中的类型或成员来查找此类转换器。 或者,属性可以引用抽象类类型或接口。 对于抽象类或接口,XAML 分析的期望是,必须使用实现该接口的实际类实例或从该抽象类派生的类型实例填充属性值。 可在抽象类上声明属性,但只能在从抽象类派生的实际类上设置属性。 这是因为,无论如何,为类创建对象元素都需要类上的公共默认构造函数。 启用了 TypeConverter 的特性语法 如果在类级别提供专用的特性化类型转换器,则应用的类型转换将为任何需要实例化该类型的属性启用特性语法。 类型转换器不启用该类型的对象元素用法;只有当存在该类型的默认构造函数时才会启用对象元素用法。 所以,启用了类型转换器的属性一般而言在属性语法中不可用,除非该类型本身也支持对象元素语法。 这一点的一个例外是,可以指定属性元素语法,但允许该属性元素包含一个字符串。 该用法实质上相当于特性语法用法,这样的用法不常见,除非需要对特性值进行更可靠的空白处理。 例如,以下用法是接受字符串的属性元素用法和等效的特性用法: XAML de-DE XAML 允许使用特性语法,但包含对象元素的属性元素语法的示例通过 XAML 禁止是采用 Cursor 类型的各个属性。 Cursor 类有专用类型转换器 CursorConverter,但未公开默认构造函数,因此 Cursor 属性只能通过特性语法进行设置,即使实际 Cursor 类型为引用类型。 每个属性类型转换器 此外,属性本身也可以在属性级别声明类型转换器。 对于基于适当类型的 ConvertFrom 操作,通过将特性的传入字符串值作为输入进行处理,这将启用“mini language”,它将实例化内联属性类型的对象。 通常这样做是为了提供方便的访问器,而不是作为的唯一手段在 XAML 中设置一个属性。 但是,对于想要使用现有 CLR 类型(不提供默认构造函数或特性化类型转换器)的特性,也可以使用类型转换器。 从 WPF API 的示例是采用 CultureInfo 类型的某些属性。 在这种情况下, WPF 使用现有 Microsoft .NET Framework CultureInfo 类型改进地址用于早期版本框架的兼容性和迁移方案,但是, CultureInfo 类型不支持必需的构造函数或类型级别的类型转换可用,因为 XAML 属性值直接。 公开具有 XAML 用法的属性时,特别当您是控件作者时,尤其应考虑使用依赖项属性支持该属性。 这是尤其如此,如果使用 XAML 处理器的现有 Windows Presentation Foundation (WPF) 实现,使用 DependencyProperty ,将返回,因为可以提高性能。 对于用户期望的 XAML 可访问属性,依赖项属性将公开该属性的属性系统功能。 这些功能 包括动画、数据绑定和样式支持。 有关更多信息,请参见自定义依赖项属性和 XAML 加载和依赖项属性。 编写和属性化类型转换器 有时需要编写自定义 TypeConverter 派生类,以便为属性类型提供类型转换。 有关如何从类型转换器派生和创建支持 XAML 用法的类型转换器,以及如何应用TypeConverterAttribute 的说明,请参见 TypeConverters 和 XAML。 有关自定义类事件的 XAML 事件处理程序特性语法的要求 若要将事件用作 CLR 事件,必须在支持默认构造函数的类上或可以在派生类中访问事件的抽象类上,将该事件公开为公共事件。 为了可方便地用作路由事件,CLR 事件应实现显式 add 和 remove 方法,这两种方法分别添加和移除 CLR 事件签名的处理程序,并将这些处理程序转发到 AddHandler 和 RemoveHandler 方法。 这些方法在事件所附加到的实例的路由事件处理程序存储区中添加或删除处理程序。 说明 可以使用 AddHandler 直接注册路由事件的处理程序,而不用特意定义用于公开路由事件的 CLR 事件。 通常建议不要这样做,因为该事件不会使 XAML 特性语法来附加处理程序,并且,生成的类将为该类型的功能提供一个不太透明 XAML 视图。 编写集合属性 接受集合类型的属性具有的 XAML 语法允许您指定要添加到集合的对象。 此语法有两种显著功能。 不需要在对象元素语法中指定属于集合对象的对象。 如果在 XAML 中指定接受集合类型的属性,则隐式存在该集合类型。 标记中该集合属性的子元素将被处理为集合的成员。 通常,代码对集合成员的访问通过列表/字典方法(如 Add)或索引器执行。 但是, XAML 语法不支持方法或索引器 (例外情况:XAML 2009 可以支持方法,但是,使用 XAML 2009 中限制可能的 WPF 用法;请参见 XAML 2009 语言功能)。 对于生成元素树的操作,集合明显是很常见的要求,您需要在声明性 XAML 中通过某种方法填充这些集合。 因此,处理集合属性的子元素的方法是将这些子元素添加到将作为集合属性类型值的集合中。 .NET framework XAML 服务实现和 WPF XAML 处理器 WPF XAML 使用以下定义构成集合属性。 属性的属性类型必须实现以下内容之一: 实现 IList。 实现 IDictionary 或等效泛型 (IDictionary 从 Array 派生 (有关 XAML 中数组的更多信息,请参见 x:Array 标记扩展。) 实现 IAddChild(WPF 定义的接口)。 每个键入 CLR 具有 Add 方法, XAML 处理器使用将项添加到基础集合,在创建对象图时。 说明 泛型 List 和 Dictionary 接口 (IList 声明接受集合的属性时,务必注意在该类型的新实例中初始化属性值的方式。 如果未将属性实现为依赖项属性,则使属性使用可调用集合类型构造函数的支持字段是合适的。 如果属性是依赖项属性,则可能需要将集合属性初始化为默认类型构造函数的一部分。 这是因为,依赖项属性从元数据中获取其默认值,并且您通常不希望集合属性的初始值为静态的共享集合。 对于每个包含类型实例,都应有一个集合实例。 有关更多信息,请参见自定义依赖项属性。 您可以为集合属性实现自定义集合类型。 由于集合属性隐式进行处理,因此自定义集合类型不需要提供默认构造函数就可以在 XAML 中隐式使用。 但是,也可以选择为集合类型提供默认构造函数。 这是一种值得推行的做法。 除非提供默认构造函数,否则无法显式地将集合声明为对象元素。 一些标记作者可能喜欢将显式集合视作一种标记样式。 另外,在创建将集合类型用作属性值的新对象时,默认构造函数可以简化初始化要求。 声明 XAML 内容属性 XAML 语言定义 XAML 内容属性的概念。 对象语法中可用的每个类恰好有一个 XAML 内容属性。 若要将属性声明为类的 XAML 内容属性,请将ContentPropertyAttribute 作为 类定义的一部分进行应用。 在属性中将要使用的 XAML 内容属性的名称指定为 Name。 属性按名称指定为字符串,不是反射构造 (如PropertyInfo。 您可以将集合属性指定为 XAML 内容属性。 这将导致使用该属性,由此对象元素可以有一个或多个子元素,而没有任何插入集合对象元素或属性元素标记。 这些元素然后被作为 XAML 内容属性的值进行处理,并添加到支持集合实例中。 有些现有 XAML 内容属性使用的属性类型 Object。 这将使 XAML 内容属性可接受基元值(如 String),并可接受单个引用对象值。 如果遵从此模型,则您的类型将负责类型确定和可能类型的处理。 使用 Object 内容类型的一般原因有两种,一种是支持将对象内容添加为字符串的简单方式(接受默认呈现处理),另一种是支持添加对象内容(指定非默认呈现或其他数据)的高级方式。 序列化 XAML 对于某些情况,例如,如果您是控件作者,您可能还需要确保在 XAML 可实例化的任何对象表示形式也可以序列化到等效的 XAML 标记。 本主题中不介绍序列化要求。 请参见控件创作概述和元素树和序列化。 标记扩展和 WPF XAML . 本主题介绍 XAML 的标记扩展概念,包括其语法规则、用途以及底层的类对象模型。 标记扩展是 XAML 语言以及 XAML 服务的 .NET 实现的常规功能。 本主题专门详细论述了用于 WPF XAML 的标记扩展。 本主题包括下列各节。 XAML 处理器和标记扩展 基本标记扩展语法 XAML 定义的标记扩展 特定于 WPF 的标记扩展 *Extension 类 转义序列和标记扩展 XAML 用法中的嵌套标记扩展 标记扩展和属性元素语法 相关主题 XAML 处理器和标记扩展 通常,XAML 分析器可将特性值解释为可转换成基元的文本字符串,或可通过某种方法将特性值转换为对象。 其中一种方法是引用类型转换器;详情请参见主题TypeConverters 和 XAML。 不过,也存在要求其他行为的情况。 例如,可以指示 XAML 处理器,特性的值不应在对象图中生成新对象。 特性应生成引用对象图另一部分中的已构造对象或引用静态对象的对象图。 另一种情况是,可以指示 XAML 处理器使用向对象构造函数提供非默认参数的语法。在这些类型的情况中,标记扩展可以提供解决方案。 基本标记扩展语法 可以实现标记扩展以便为特性用法中的属性和/或属性元素用法中的属性提供值。 当用于提供特性值时,将标记扩展序列与 XAML 处理器区分开的语法就是左右大括号({ 和 })。 然后,由紧跟在左大括号后面的字符串标记来标识标记扩展的类型。 当用在属性元素语法中时,标记扩展在外观上与其他任何用于提供属性元素值的元素相同,即:一个将标记扩展类作为一个元素引用并以尖括号 (<>) 括起的 XAML 元素声明。 XAML 定义的标记扩展 有几个标记扩展并非是 XAML 的 WPF 实现所特有的,而是语言形式的 XAML 的内部函数或功能实现。 这些标记扩展在 程序集中作为常规 .NET Framework XAML 服务的一部分而实现,并且位于 XAML 语言 XAML 命名空间中。 就常见标记用法而言,这些标记扩展通常可由用法中的 x: 前缀标识。MarkupExtension 基类(也在 中定义)提供了所有标记扩展均应使用的模式,以便在 XAML 读取器和 XAML 编写器中得到支持(包括在 WPF XAML 中得到支持)。 x:Type 为命名类型提供 Type 对象。 此工具最常用于样式和模板。 有关详细信息,请参见 x:Type 标记扩展。 x:Static 生成静态值。 这些值来自不直接是目标属性值的类型、但可以计算为该类型的值类型代码实体。 有关详细信息,请参见 x:Static 标记扩展。 x:Null 将 null 指定为属性的值,可用于特性或属性元素值。 有关详细信息,请参见 x:Null 标记扩展。 在特意不使用 WPF 基元素和控件模型提供的集合支持的情况下,x:Array 为 XAML 语法中常规数组的创建提供支持。 有关详细信息,请参见 x:Array 标记扩展。 说明 x: 前缀在 XAML 文件或生产的根元素中用于 XAML 语言内部函数的典型 XAML 命名空间映射。 例如,WP启动 XAML 文件。 您可以在自己的 XAML 命名空间映射中选择不同的前缀标记,但本文档将采用默认的 x: 名空间已定义部分的那些实体,这与 WPF 默认命名空间或与特定框架不相关的其他 XAML 命名空间相反。 特定于 WPF 的标记扩展 WPF 编程中最常用的标记扩展是支持资源引用的标记扩展(StaticResource 和 DynamicResource)以及支持数据绑定的标记扩展 (Binding)。 StaticResource 通过替换已定义资源的值来为属性提供值。 StaticResource 计算最终在 XAML 加载时进行,并且在运行时没有访问对象图的权限。有关详细信息,请参见 StaticResource 标记扩展。 DynamicResource 通过将值推迟为对资源的运行时引用来为属性提供值。 动态资源引用强制在每次访问此类资源时都进行新查找,并在运行时有权访问对象图。 为了获取此访问权限,WPF 属性系统中的依赖项属性和计算出的表达式支持 DynamicResource 概念。 因此,对于依赖项属性目标,您只能使用DynamicResource。 有关详细信息,请参见 DynamicResource 标记扩展。


发布评论