XAML 概述

本文向 Windows 运行时应用开发人员受众介绍了 XAML 语言和 XAML 概念,并介绍了在 XAML 中声明对象和设置属性的不同方法,因为它用于创建 Windows 运行时应用。

什么是 XAML?

可扩展应用程序标记语言(XAML)是一种声明性语言。 具体而言,XAML 可以使用语言结构初始化对象和设置对象的属性,该结构显示多个对象之间的分层关系,以及支持类型扩展的后盾类型约定。 可以在声明性 XAML 标记中创建可见的 UI 元素。 然后,可以为每个 XAML 文件关联单独的后台代码文件,该文件可以响应事件并操作最初在 XAML 中声明的对象。

XAML 语言支持在开发过程中的不同工具和角色之间交换源,例如在设计工具与交互式开发环境(IDE)之间交换 XAML 源,或者在主要开发人员和本地化开发人员之间交换 XAML 源。 通过使用 XAML 作为交换格式,设计师角色和开发人员角色可以保持独立或整合在一起,设计师和开发人员可以在应用生产期间进行迭代开发。

在 Windows 运行时应用项目中看到它们时,XAML 文件是扩展名为 .xaml 文件扩展名的 XML 文件。

基本 XAML 语法

XAML 具有基于 XML 的基本语法。 根据定义,有效的 XAML 也必须是有效的 XML。 但 XAML 还具有语法概念,这些概念分配了不同的更完整的含义,同时仍根据 XML 1.0 规范在 XML 中有效。 例如,XAML 支持 属性元素语法,其中可以在元素中设置属性值,而不是属性或内容中的字符串值。 对于常规 XML,XAML 属性元素是名称中包含点的元素,因此对纯 XML 有效,但含义不相同。

XAML 和 Visual Studio

Microsoft Visual Studio 可帮助生成有效的 XAML 语法,无论是在 XAML 文本编辑器中,还是更图形化的 XAML 设计图面。 使用 Visual Studio 为应用编写 XAML 时,请不要担心每个击键的语法。 IDE 通过提供自动完成提示、在 Microsoft IntelliSense 列表和下拉菜单中显示建议、在 工具箱 窗口中展示 UI 元素库,或使用其他技术,来鼓励使用有效的 XAML 语法。 如果这是你第一次使用 XAML 的体验,那么在引用或其他主题中描述 XAML 语法时,了解语法规则,尤其是有时用于描述限制或选择的术语可能很有用。 XAML 语法的细点在单独的主题 XAML 语法指南中介绍。

XAML 命名空间

在一般编程中,命名空间是一个组织概念,用于确定如何解释编程实体的标识符。 通过使用命名空间,编程框架可以将用户声明的标识符与框架声明的标识符分开,通过命名空间限定来消除标识符的歧义,强制实施范围名称规则等。 XAML 有自己的 XAML 命名空间概念,用于实现 XAML 语言的目的。 下面是 XAML 如何应用和扩展 XML 语言命名空间概念:

  • XAML 将保留的 XML 属性 xmlns 用于命名空间声明。 特性的值通常是统一资源标识符(URI),这是从 XML 继承的约定。
  • XAML 在声明中使用前缀来声明非默认命名空间,元素和属性中的前缀用法引用该命名空间。
  • XAML 具有默认命名空间的概念,这是在使用或声明中不存在前缀时使用的命名空间。 可以为每个 XAML 编程框架以不同的方式定义默认命名空间。
  • 命名空间定义继承在 XAML 文件或构造中,从父元素继承到子元素。 例如,如果在 XAML 文件的根元素中定义命名空间,则该文件中的所有元素都继承该命名空间定义。 如果页面中的元素进一步重新定义命名空间,该元素的后代将继承新定义。
  • 元素的属性继承元素的命名空间。 在 XAML 属性上看到前缀相当罕见。

XAML 文件几乎总是在其根元素中声明默认 XAML 命名空间。 默认 XAML 命名空间定义可以在不按前缀限定的情况下声明的元素。 对于典型的 Windows 运行时应用项目,此默认命名空间包含用于 UI 定义的 Windows 运行时的所有内置 XAML 词汇:默认控件、文本元素、XAML 图形和动画、数据绑定和样式支持类型等。 因此,为 Windows 运行时应用编写的大多数 XAML 都能够避免在引用常见 UI 元素时使用 XAML 命名空间和前缀。

下面是一个代码片段,显示了应用程序初始页面的模板创建的Page根节点(仅显示开头标记,并进行了简化)。 它声明默认命名空间,以及 x 命名空间(我们将下一步介绍)。

<Page
    x:Class="Application1.BlankPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
>

XAML 语言的 XAML 命名空间

几乎每个 Windows 运行时 XAML 文件中声明的一个特定 XAML 命名空间是 XAML 语言命名空间。 此命名空间包括 XAML 语言规范定义的元素和概念。 按照约定,XAML 语言 XAML 命名空间映射到前缀“x”。 Windows 运行时应用项目的默认项目和文件模板始终将默认 XAML 命名空间(无前缀,只是 xmlns=)和 XAML 语言 XAML 命名空间(前缀“x”)定义为根元素的一部分。

“x”前缀/XAML 语言 XAML 命名空间包含一些经常在 XAML 中使用的编程构造。 下面是最常见的方法:

术语 Description
x:Key 为 XAML ResourceDictionary 中的每个资源设置唯一的用户定义密钥。 密钥的令牌字符串是 StaticResource 标记扩展的参数,稍后使用此密钥从应用 XAML 中的其他位置的其他 XAML 用法中检索 XAML 资源。
x:Class 指定代码命名空间和代码类名称,用于提供 XAML 页的后台代码的类。 当您构建应用程序时,这用于命名由构建操作创建或加入的类。 这些生成操作为 XAML 标记编译器提供支持,并在编译应用程序时合并标记和后台代码。 必须有这样的类来支持 XAML 页面使用后台代码。 默认 Windows 运行时激活模型中的 Window.Content
x:Name 指定在处理 XAML 中定义的对象元素后存在于运行时代码中的实例的运行时对象名称。 可以将 XAML 中的 x:Name 设置为类似于在代码中声明命名变量。 稍后你会了解到,这正是当 XAML 作为 Windows 运行时应用的组件加载时所发生的情况。
注意Name 是框架中的类似属性,但并非所有元素都支持它。 只要该元素类型不支持 FrameworkElement.Name,就使用 x:Name 进行元素标识。
x:Uid 标识应对其某些属性值使用本地化资源的元素。 有关如何使用 x:Uid 的详细信息,请参阅 快速入门:翻译 UI 资源
XAML 内部数据类型 当属性或资源需要这些类型时,这些类型可以为简单值类型指定值。 这些内部类型对应于通常定义为每个编程语言内部定义的一部分的简单值类型。 例如,您可能需要一个表示 Boolean 值 true 的对象,以便在 ObjectAnimationUsingKeyFrames 的情节提要视觉状态中使用。 对于 XAML 中的该值,你将使用 x:Boolean 内部类型作为对象元素,如下所示: <x:Boolean>True</x:Boolean>

XAML 语言 XAML 命名空间中的其他编程构造存在,但并不常见。

将自定义类型映射到 XAML 命名空间

XAML 作为语言最强大的方面之一是,可以轻松扩展 Windows 运行时应用的 XAML 词汇。 可以在应用的编程语言中定义自己的自定义类型,然后在 XAML 标记中引用自定义类型。 通过自定义类型对扩展的支持从根本上内置于 XAML 语言的工作原理。 框架或应用开发人员负责创建 XAML 引用的后盾对象。 框架和应用开发人员都不受任何词汇中对象所表示功能的规范约束,仅需遵循基本的 XAML 语法规则。 对于 XAML 语言的 XAML 命名空间类型应执行什么操作,有一些期望,但 Windows 运行时提供了所有必要的支持。

如果将 XAML 用于来自除 Windows 运行时核心库和元数据之外的库的类型,则必须声明并映射带有前缀的 XAML 命名空间。 在元素用法中使用该前缀来引用库中定义的类型。 将前缀映射声明为 xmlns 属性,通常与其他 XAML 命名空间定义一起在根元素中。

若要创建引用自定义类型的自己的命名空间定义,请先指定关键字 xmlns:,然后指定所需的前缀。 该特性的值必须包含关键字 ,使用: 作为值的第一部分。 值的其余部分是一个字符串标记,它按名称引用包含自定义类型的特定代码支持命名空间。

该前缀定义标记标记,该标记用于在该 XAML 文件中的其余标记中引用该 XAML 命名空间。 冒号字符(:)位于前缀和要引用的 XAML 命名空间中的实体之间。

例如,将前缀 myTypes 映射到命名空间 myCompany.myTypes 的属性语法为: xmlns:myTypes="using:myCompany.myTypes",代表性元素用法为: <myTypes:CustomButton/>

有关映射自定义类型的 XAML 命名空间的详细信息,包括 Visual C++ 组件扩展(C++/CX)的特殊注意事项),请参阅 XAML 命名空间和命名空间映射

其他 XAML 命名空间

通常会看到定义前缀“d”(用于设计器命名空间)和“mc”(用于标记兼容性)的 XAML 文件。 通常,这些功能用于支持基础设施或在设计时工具中启用场景。 有关详细信息,请参阅 XAML 命名空间主题的“其他 XAML 命名空间”部分

标记扩展

标记扩展是一种 XAML 语言概念,通常用于 Windows 运行时 XAML 实现。 标记扩展通常表示某种“快捷方式”,使 XAML 文件能够访问一个值或行为,这些值或行为不是简单地声明基于支持类型的元素。 某些标记扩展可以使用纯字符串或附加嵌套元素来设置属性,目的是简化不同 XAML 文件之间的语法或分解。

在 XAML 属性语法中,大括号“{”和“}”表示 XAML 标记扩展用法。 此用法指示 XAML 处理方法,从一般将属性值处理为文本字符串或直接可转换的字符串值的方式中跳出。 相反,XAML 分析程序会调用为该特定标记扩展提供行为的代码,该代码提供 XAML 分析程序所需的备用对象或行为结果。 标记扩展可以具有参数,这些参数遵循标记扩展名称,并且也包含在大括号内。 通常,经过评估的标记扩展返回一个对象值。 在解析过程中,返回值将被插入到对象树中源 XAML 文件中标记扩展用法所在的位置。

Windows 运行时 XAML 支持在默认 XAML 命名空间下定义的这些标记扩展,并由 Windows 运行时 XAML 分析器理解:

  • {x:Bind}: 支持数据绑定,该绑定通过执行在编译时生成的特殊用途代码来延迟属性评估,直到运行时。 此标记扩展支持各种参数。
  • {Binding}:支持数据绑定,它通过执行常规用途运行时对象检查来延迟属性评估,直到运行时。 此标记扩展支持各种参数。
  • {StaticResource}:支持引用 ResourceDictionary 中定义的资源值。 这些资源可以位于不同的 XAML 文件中,但最终必须在加载时由 XAML 分析器找到。 在 {StaticResource} 的使用中,参数标识 ResourceDictionary 中键控资源的键名。
  • {ThemeResource}:类似于 {StaticResource} ,但可以响应运行时主题更改。 {ThemeResource} 经常出现在 Windows 运行时默认 XAML 模板中,因为这些模板中的大多数都旨在与用户在运行应用时切换主题兼容。
  • {TemplateBinding}{Binding} 的一种特殊情况,它支持 XAML 中的控件模板及其在运行时的最终用法。
  • {RelativeSource}:启用模板绑定的特定形式,其中值来自模板化父级。
  • {CustomResource}:适用于高级资源查找方案。

Windows 运行时还支持 {x:Null} 标记扩展。 使用此方法可以在 XAML 中将 可空 的值设置为 null。 例如,可以在 CheckBox 的控件模板中使用它,该模板将 null 解释为不确定的检查状态(触发“不确定”视觉状态)。

标记扩展通常从应用的对象图的一些其他部分返回现有实例,或者将值推迟到运行时。 由于可以将标记扩展作为属性值使用,这是典型的用法,因此经常看到标记扩展为本来可能需要属性元素语法的引用类型属性提供值。

例如,下面是从 ResourceDictionary 引用可重用样式的语法: <Button Style="{StaticResource SearchButtonStyle}"/>样式是引用类型,而不是简单的值。因此,如果不使用{StaticResource},就需要有一个<Button.Style>属性元素,并在其中进行<Style>定义,才能设置FrameworkElement.Style属性。

通过使用标记扩展,XAML 中可设置的每个属性都可能在属性语法中设置。 即使某属性不支持直接使用属性语法进行对象实例化,你仍然可以使用属性语法为其提供引用值。 或者,可以启用特定的行为,以延迟 XAML 属性由值类型或新创建的引用类型填充的一般要求。

为了说明,下一个 XAML 示例使用属性语法设置 BorderFrameworkElement.Style 属性的值。 该 FrameworkElement.Style 属性采用 Style 类的实例,默认情况下无法使用属性语法字符串创建引用类型。 但在这种情况下,该属性引用特定的标记扩展 StaticResource。 处理该标记扩展时,它将返回对先前定义为资源字典中键式资源的 Style 元素的引用。

<Canvas.Resources>
  <Style TargetType="Border" x:Key="PageBackground">
    <Setter Property="BorderBrush" Value="Blue"/>
    <Setter Property="BorderThickness" Value="5"/>
  </Style>
</Canvas.Resources>
...
<Border Style="{StaticResource PageBackground}">
  ...
</Border>

可以嵌套标记扩展。 首先评估最内部的标记扩展。

由于标记扩展,需要在属性中使用文本“{”值的特殊语法。 有关详细信息,请参阅 XAML 语法指南

事件

XAML 是对象的声明性语言及其属性,但它还包括用于将事件处理程序附加到标记中的对象的语法。 然后,XAML 事件语法可以通过 Windows 运行时编程模型集成 XAML 声明的事件。 将事件的名称指定为处理事件的对象的属性名称。 对于属性值,指定在代码中定义的事件处理程序函数的名称。 XAML 处理器使用此名称在加载的对象树中创建委托表示形式,并将指定的处理程序添加到内部处理程序列表中。 几乎所有的 Windows 运行时应用都由标记和代码隐藏源定义。

下面是一个简单的示例。 Button 类支持名为 Click 的事件。 可以为 Click 编写一个处理程序,该 处理程序 运行在用户单击 按钮后应调用的代码。 在 XAML 中,将 Click 指定为 按钮上的属性。 对于属性值,请提供一个字符串,该字符串是处理程序的方法名称。

<Button Click="showUpdatesButton_Click">Show updates</Button>

编译时,编译器现在预期在 XAML 页的 x:Class 值中声明的命名空间中,代码隐藏文件将定义一个名为showUpdatesButton_Click的方法。 此外,该方法必须满足 Click 事件的委托协定。 例如:

namespace App1
{
    public sealed partial class MainPage: Page {
        ...
        private void showUpdatesButton_Click (object sender, RoutedEventArgs e) {
            //your code
        }
    }
}
' Namespace included at project level
Public NotInheritable Class MainPage
    Inherits Page
        ...
        Private Sub showUpdatesButton_Click (sender As Object, e As RoutedEventArgs e)
            ' your code
        End Sub
    ...
End Class
namespace winrt::App1::implementation
{
    struct MainPage : MainPageT<MainPage>
    {
        ...
        void showUpdatesButton_Click(Windows::Foundation::IInspectable const&, Windows::UI::Xaml::RoutedEventArgs const&);
    };
}
// .h
namespace App1
{
    public ref class MainPage sealed {
        ...
    private:
        void showUpdatesButton_Click(Object^ sender, RoutedEventArgs^ e);
    };
}

在项目中,XAML 会编写为 .xaml 文件,并使用您首选的语言(C#、Visual Basic、C++/CX)编写后台代码文件。 当 XAML 文件作为项目生成操作的一部分进行标记编译时,通过将命名空间和类指定为 XAML 页面根元素的 x:Class 属性来标识每个 XAML 页面的代码隐藏文件的位置。 有关这些机制如何在 XAML 中工作以及它们与编程和应用程序模型的关系的详细信息,请参阅 事件和路由事件概述

注释

对于C++/CX,有两个代码隐藏文件:一个是标头(.xaml.h),另一个是实现(.xaml.cpp)。 实现参考了头文件,而技术上,正是这个头文件代表了代码隐藏连接的入口点。

资源字典

创建 ResourceDictionary 是一项常见任务,通常通过将资源字典创作为 XAML 页面或单独的 XAML 文件的区域来完成。 资源字典及其用法是本主题范围之外的较大概念区域。 有关详细信息,请参阅 ResourceDictionary 和 XAML 资源引用

XAML 和 XML

XAML 语言从根本上基于 XML 语言。 但 XAML 会显著扩展 XML。 特别是,由于架构与后盾类型概念的关系,对架构概念的处理方式截然不同,并添加了附加成员和标记扩展等语言元素。 xml:lang 在 XAML 中有效,但影响运行时,而不是分析行为,并且通常别名为框架级属性。 有关详细信息,请参阅 FrameworkElement.Languagexml:base 在标记中有效,但分析程序忽略它。 xml:space 有效,但仅适用于 XAML 和空格 主题中描述的方案。 编码属性在 XAML 中有效。 仅支持 UTF-8 和 UTF-16 编码。 不支持 UTF-32 编码。

XAML 中的区分大小写

XAML 区分大小写。 这是 XAML 基于 XML 的另一个后果,它区分大小写。 XAML 元素和属性的名称区分大小写。 属性的值可能区分大小写;这取决于如何处理特定属性的属性值。 例如,如果属性值声明枚举的成员名称,则类型转换成员名称字符串以返回枚举成员值的内置行为不区分大小写。 相比之下,Name 属性的值、以及基于 Name 属性声明的名称来处理对象的实用方法,将名称字符串视为区分大小写。

XAML 名称范围

XAML 语言定义 XAML 名称范围的概念。 XAML 名称范围概念影响 XAML 处理器应如何处理应用于 XAML 元素的 x:NameName 的值,尤其是应依赖名称作为唯一标识符的范围。 XAML 名称范围在单独的主题中更详细地介绍;请参阅 XAML 名称范围

XAML 在开发过程中的角色

XAML 在应用开发过程中扮演了几个重要角色。

  • 如果使用的是 C#、Visual Basic 或 C++/CX 进行编程,则 XAML 是声明该 UI 中应用 UI 和元素的主要格式。 通常,项目中至少有一个 XAML 文件表示应用中最初显示的 UI 的页面隐喻。 其他 XAML 文件可能会声明用于导航 UI 的其他页面。 其他 XAML 文件可以声明资源,例如模板或样式。
  • 使用 XAML 格式声明应用于应用的控件和 UI 的样式和模板。
  • 可以使用样式和模板来模板化现有控件,或者定义一个控件,该控件提供默认模板作为控件包的一部分。 使用它定义样式和模板时,相关 XAML 通常声明为具有 ResourceDictionary 根的离散 XAML 文件。
  • XAML 是设计器支持创建应用 UI 并在不同设计器应用之间交换 UI 设计的常见格式。 最值得注意的是,应用 XAML 可以在不同的 XAML 设计工具(或工具中的设计窗口)之间交换。
  • 其他几种技术还定义了 XAML 中的基本 UI。 Windows 运行时的 XAML 与 Windows Presentation Foundation (WPF) XAML 和 Microsoft Silverlight XAML 共用相同的 URI 作为其共享的默认 XAML 命名空间。 Windows 运行时的 XAML 词汇与在 Silverlight 和较小程度上在 WPF 中使用的用于 UI 的 XAML 词汇有显著重叠。 因此,XAML 促进了一条有效的迁移路径,适用于最初为前身技术(也使用XAML)定义的UI。
  • XAML 定义 UI 的视觉外观,关联的代码隐藏文件定义逻辑。 可以调整 UI 设计,而无需更改后置代码中的逻辑。 XAML 简化了设计器和开发人员之间的工作流。
  • 由于可视化设计器的丰富性和对 XAML 语言的设计图面支持,XAML 在早期开发阶段支持快速 UI 原型。

根据自己在开发过程中的角色,你可能不会与 XAML 交互太多。 与 XAML 文件交互的程度也取决于所使用的开发环境、是否使用交互式设计环境功能(如工具箱和属性编辑器),以及 Windows 运行时应用的范围和用途。 不过,在开发应用的过程中,可能会使用文本或 XML 编辑器在元素级别编辑 XAML 文件。 使用此信息,您可以在文本或 XML 表示形式中自信地编辑 XAML,并确保当工具、标记编译操作或 Windows 运行时应用的运行时阶段使用该 XAML 文件时,保持其声明的有效性和用途的正确性。

优化 XAML 以提升负载性能

下面是使用性能最佳做法在 XAML 中定义 UI 元素的一些提示。 其中许多提示都与使用 XAML 资源有关,但为了方便起见,一般 XAML 概述中在此处列出。 有关 XAML 资源的详细信息,请参阅 ResourceDictionary 和 XAML 资源引用。 有关性能的更多提示,包括旨在演示在 XAML 中应避免的一些性能不佳做法的 XAML,请参阅 “优化 XAML 标记”。

  • 如果在 XAML 中经常使用相同的颜色画笔,请将 SolidColorBrush 定义为资源,而不是每次将命名颜色用作属性值。
  • 如果在多个 UI 页面上使用相同的资源,请考虑在 Application.Resources 中定义它,而不是在每个页面上定义它。 相反,如果只有一个页面使用资源,请不要在 Application.Resources 中定义它,而是只为需要它的页面定义它。 这对在设计应用过程中进行 XAML 分解以及在 XAML 解析期间的性能优化都是有益的。
  • 对于应用包的资源,请检查未使用的资源(具有密钥的资源,但应用中没有 StaticResource 引用)。 在发布应用之前,请从 XAML 中删除这些内容。
  • 如果使用提供设计资源(MergedDictionaries)的单独 XAML 文件,请考虑注释或删除这些文件中未使用的资源。 即使你有一个用于多个应用或为所有应用提供公共资源的共享 XAML 起点,每个应用仍然需要单独打包这些 XAML 资源,并可能需要加载它们。
  • 不要定义不需要组合的 UI 元素,并尽可能使用默认控件模板(这些模板已经过测试并验证负载性能)。
  • 使用 边框 等容器,而不是故意过度绘制 UI 元素。 基本上,不要多次绘制相同的像素。 有关过度绘制以及如何对其进行测试的详细信息,请参阅 DebugSettings.IsOverdrawHeatMapEnabled
  • 使用 ListViewGridView 的默认项模板;这些属性具有特殊的 演示器 逻辑,用于解决为大量列表项生成可视化树时的性能问题。

调试 XAML

由于 XAML 是标记语言,因此在 Microsoft Visual Studio 中调试的某些典型策略不可用。 例如,无法设置 XAML 文件中的断点。 但是,还有其他技术可以帮助你在开发应用时调试 UI 定义或其他 XAML 标记的问题。

当 XAML 文件出现问题时,最典型的结果是某些系统或应用将引发 XAML 分析异常。 每当出现 XAML 分析异常时,XAML 分析器加载的 XAML 将无法创建有效的对象树。 在某些情况下,例如当 XAML 表示应用程序加载为根视觉对象的第一个“页面”时,XAML 解析异常是不可恢复的。

XAML 通常在 IDE(如 Visual Studio)及其 XAML 设计图面之一中进行编辑。 在编辑 XAML 源时,Visual Studio 通常会提供设计时验证和错误检查。 例如,在键入错误的属性值后,它可能会立即在 XAML 文本编辑器中显示“波浪线”提示,而您甚至无需等待 XAML 编译过程就能发现 UI 定义中的问题。

应用实际运行后,如果设计时未检测到任何 XAML 分析错误,公共语言运行时(CLR)会报告这些错误作为 XamlParseException。 有关在运行时遇到 XamlParseException 时可以采取的措施的详细信息,请参阅 C# 或 Visual Basic 中 Windows 运行时应用的异常处理

注释

使用 C++/CX 编写代码的应用程序不会导致特定的 XamlParseException。 但异常中的消息阐明了错误的来源与 XAML 相关,并包括上下文信息,如 XAML 文件中的行号,就像 XamlParseException 那样。

有关调试 Windows 运行时应用的详细信息,请参阅 “启动调试会话”。