XAML 概述

本文介绍 XAML 语言的功能,并演示如何使用 XAML 编写 Windows Presentation Foundation (WPF) 应用。 本文专门介绍 WPF 实现的 XAML。 XAML 本身是比 WPF 更大的语言概念。

什么是 XAML

XAML 是一种声明性标记语言。 应用于 .NET 编程模型时,XAML 简化了为 .NET 应用创建 UI。 可以在声明性 XAML 标记中创建可见的 UI 元素,然后使用与标记通过分部类定义连接的后台代码文件,将 UI 定义与运行时逻辑分开。 XAML 直接表示在程序集定义的一组特定支持类型中的对象实例化。 大多数其他标记语言与这种情况不同,它们通常是解释性语言,与支撑类型系统无直接联系。 XAML 支持一个工作流,其中单独的参与方可以使用可能不同的工具处理 UI 和应用的逻辑。

以文本形式表示时,XAML 文件是通常具有扩展名的 .xaml XML 文件。 文件可以通过任何 XML 编码进行编码,但编码为 UTF-8 是典型的。

以下示例演示如何在 UI 中创建按钮。 此示例旨在让你了解 XAML 如何表示常见的 UI 编程隐喻(这不是完整的示例)。

<StackPanel>
    <Button Content="Click Me"/>
</StackPanel>

简要介绍 XAML 语法

以下部分介绍了 XAML 语法的基本形式,并提供了一个简短的标记示例。 这些部分不打算提供有关每种语法形式的完整信息,例如这些语法形式在后备类型系统中的表示方式。 有关 XAML 语法的详细信息,请参阅 XAML 语法详细信息

如果你以前熟悉 XML 语言,接下来的几个部分中的大部分材料都基本。 这是 XAML 的基本设计原则之一的结果。 XAML 语言定义自己的概念,但这些概念在 XML 语言和标记表单中起作用。

XAML 对象元素

对象元素通常声明类型的实例。 使用 XAML 作为语言的技术引用的程序集定义了该类型。

对象元素语法始终以左尖括号 (<) 开头。 后跟要在其中创建实例的类型的名称。 (名称可以包含前缀,稍后将解释的概念。之后,可以选择在对象元素上声明属性。 若要完成对象元素标记,请以右尖括号 (>) 结尾。 相反,可以使用一种不包含任何内容的自闭合形式,而这种形式是通过连续使用正斜杠和右尖括号来完成标签的。/> 例如,再次查看前面显示的标记代码片段。

<StackPanel>
    <Button Content="Click Me"/>
</StackPanel>

这指定了两个对象元素:<StackPanel>(包含内容,并在稍后的结束标记),以及<Button .../>(具有多个属性的自闭合形式)。 对象元素 StackPanelButton 每个元素都映射到由 WPF 定义的类的名称,并且是 WPF 程序集的一部分。 指定对象元素标记时,请创建 XAML 处理指令以创建基础类型的新实例。 在分析和加载 XAML 时,通过调用基础类型的无参数构造函数来创建每个实例。

属性语法(属性)

对象的属性通常可表示为对象元素的属性。 属性语法将正在设置的对象属性命名,后跟赋值运算符 (=)。 属性的值始终指定为引号中包含的字符串。

属性语法是最简化的属性设置语法,是用于过去使用标记语言的开发人员最直观的语法。 例如,以下标记创建一个按钮,该按钮具有红色文本和蓝色背景,显示文字为 Content

<Button Background="Blue" Foreground="Red" Content="This is a button"/>

属性元素语法

对于对象元素的某些属性,不能使用属性语法,因为提供属性值所需的对象或信息不能在属性语法的引号和字符串限制中充分表达。 对于这些情况,可以使用称为属性元素语法的不同语法。

属性元素开始标记的语法为 <TypeName.PropertyName>. 通常,该标记的内容是属性值所对应类型的对象元素。 指定内容后,必须使用结束标记关闭属性元素。 结束标记的语法为 </TypeName.PropertyName>.

如果属性语法可行,则使用特性语法通常更方便,并且启用更紧凑标记,但通常只是样式问题,而不是技术限制。 下面的示例展示了与前面属性语法示例中相同的属性设置,但这次是通过属性元素语法来设置Button的所有属性。

<Button>
    <Button.Background>
        <SolidColorBrush Color="Blue"/>
    </Button.Background>
    <Button.Foreground>
        <SolidColorBrush Color="Red"/>
    </Button.Foreground>
    <Button.Content>
        This is a button
    </Button.Content>
</Button>

集合语法

XAML 语言包括一些可生成更多可读标记的优化。 一种这样的优化是,如果特定属性采用集合类型,则在标记中声明为该属性的值中的子元素的项将成为集合的一部分。 在这种情况下,子对象元素的集合是设置为集合属性的值。

以下示例显示了用于设置属性值的 GradientStops 集合语法。

<LinearGradientBrush>
    <LinearGradientBrush.GradientStops>
        <!-- no explicit new GradientStopCollection, parser knows how to find or create -->
        <GradientStop Offset="0.0" Color="Red" />
        <GradientStop Offset="1.0" Color="Blue" />
    </LinearGradientBrush.GradientStops>
</LinearGradientBrush>

XAML 内容属性

XAML 指定一种语言功能,其中一个类可以指定其属性之一作为 XAML 内容 属性。 该对象元素的子元素用于设置该内容属性的值。 换句话说,特有地针对内容属性,在 XAML 标记中设置该属性时可以省略属性元素,以便在标记中更明显地表现父/子隐喻。

例如,Border 指定了 内容 属性 Child。 以下两 Border 个元素的处理方式相同。 第一个利用内容属性语法并省略 Border.Child 属性元素。 第二个显式显示 Border.Child

<Border>
    <TextBox Width="300"/>
</Border>
<!--explicit equivalent-->
<Border>
    <Border.Child>
        <TextBox Width="300"/>
    </Border.Child>
</Border>

作为 XAML 语言的规则,XAML 内容属性的值必须在该对象元素上的任何其他属性元素之前或之后完全提供。 例如,以下标记编译失败。

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

有关 XAML 语法的详细信息,请参阅 XAML 语法详细信息

文本内容

少量 XAML 元素可以直接处理文本作为其内容。 若要启用此功能,以下情况之一必须成立:

  • 该类必须声明内容属性,并且内容属性必须是可分配给字符串的类型(类型可以是)。Object 例如,任何ContentControl使用Content作为其内容属性和类型Object,这支持在ContentControl上的以下用法,比如Button<Button>Hello</Button>

  • 该类型必须声明类型转换器,在这种情况下,文本内容用作该类型转换器的初始化文本。 例如, <Brush>Blue</Brush> 将内容值 Blue 转换为画笔。 在实践中,这种情况不太常见。

  • 该类型必须是已知的 XAML 语言基元。

内容属性与集合语法的组合

请考虑此示例。

<StackPanel>
    <Button>First Button</Button>
    <Button>Second Button</Button>
</StackPanel>

此处,每个Button都是StackPanel的子元素。 这是一个简化和直观的标记,省略两个标记的原因有两个不同的原因。

<StackPanel>
    <StackPanel.Children>
        <!--<UIElementCollection>-->
        <Button>First Button</Button>
        <Button>Second Button</Button>
        <!--</UIElementCollection>-->
    </StackPanel.Children>
</StackPanel>

属性语法(事件)

属性语法还可用于事件而不是属性的成员。 在这种情况下,属性的名称是事件的名称。 在 XAML 事件的 WPF 实现中,特性的值是实现该事件的委托的处理程序的名称。 例如,以下标记将事件处理器 Click 分配给在标记中创建的 Button

<Button Click="Button_Click" >Click Me!</Button>

WPF 中的事件和 XAML 不仅仅限于特性语法的这个示例。 例如,你可能会想知道这里引用的ClickHandler代表什么以及它是如何定义的。 本文的即将到来的 事件和 XAML 代码隐藏 部分将对此进行说明。

XAML 中的大小写和空格

通常,XAML 区分大小写。 为了解释支持类型,WPF XAML 的大小写敏感规则与 CLR 一致。 对象元素、属性元素和属性名称都必须通过使用敏感大小写来指定,方法是将名称与程序集中的基础类型或类型的成员进行比较。 XAML 语言关键字和基元也区分大小写。 值并不总是区分大小写。 根据与使用该值的属性相关联的类型转换器的行为或属性值的类型,值的区分大小写将有所不同。 例如,采用 Boolean 该类型的属性可以采用 trueTrue 作为等效值,但前提是字符串 Boolean 的本机 WPF XAML 分析器类型转换已允许这些值作为等效值。

WPF XAML 处理器和序列化程序将忽略或删除所有不重要的空格,并将规范化任何重要的空白。 这与 XAML 规范的默认空白行为建议一致。 只有在 XAML 内容属性中指定字符串时,此行为才会产生后果。 在最简单的术语中,XAML 会将空格、换行符和制表符转换为一个空格,并在连续字符串的任一端保留一个空格。 本文未介绍 XAML 空白处理的完整说明。 有关详细信息,请参阅 XAML 中的空白处理

标记扩展

标记扩展是 XAML 语言概念。 用于提供属性语法的值时,大括号 ({}) 指示标记扩展用法。 此用法指示 XAML 处理,以不同于一般将属性值作为文本字符串或字符串可转换值处理的方式来处理它。

WPF 应用编程中使用的最常见标记扩展有 Binding(用于数据绑定表达式)以及资源引用 StaticResourceDynamicResource。 通过使用标记扩展,可以使用属性语法为属性提供值,即使该属性通常不支持属性语法。 标记扩展通常使用中间表达式类型来启用诸如延迟值或引用仅在运行时存在的其他对象等功能。

例如,以下标记使用属性语法设置 Style 属性的值。 该 Style 属性采用类的 Style 实例,默认情况下无法通过属性语法字符串实例化该类。 但在这种情况下,该属性引用特定的标记扩展 StaticResource。 处理该标记扩展时,它将返回对以前作为资源字典中的键式资源实例化的样式的引用。

<Window x:Class="index.Window1"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="Window1" Height="100" Width="300">
    <Window.Resources>
        <SolidColorBrush x:Key="MyBrush" Color="Gold"/>
        <Style TargetType="Border" x:Key="PageBackground">
            <Setter Property="BorderBrush" Value="Blue"/>
            <Setter Property="BorderThickness" Value="5" />
        </Style>
    </Window.Resources>
    <Border Style="{StaticResource PageBackground}">
        <StackPanel>
            <TextBlock Text="Hello" />
        </StackPanel>
    </Border>
</Window>

有关特定于 WPF 中实现的 XAML 的所有标记扩展的参考列表,请参阅 WPF XAML 扩展。 有关由 System.Xaml 定义并广泛用于 .NET XAML 实现的标记扩展的参考列表,请参阅 XAML 命名空间 (x:) 语言功能。 有关标记扩展概念的详细信息,请参阅 标记扩展和 WPF XAML

类型转换器

在“简短”部分中的 XAML 语法 中,它指出属性值必须由字符串设置。 字符串转换为其他对象类型或基元值的基本处理方式基于String类型本身,以及特定类型如DateTimeUri的本机处理。 但是,许多 WPF 类型或这些类型的成员以某种方式扩展了基本字符串属性处理行为,以便可以将更复杂的对象类型的实例指定为字符串和属性。

Thickness 结构是一个示例,其中类型转换已为 XAML 用法启用。 Thickness 指示嵌套矩形中的度量值,并用作属性的值,例如 Margin。 在 Thickness 上放置类型转换器后,所有使用 Thickness 的属性在 XAML 中更容易指定,因为它们可以作为属性进行指定。 以下示例使用类型转换和属性语法为 Margin 提供一个值:

<Button Margin="10,20,10,30" Content="Click me"/>

前面的属性语法示例等效于以下更详细的语法示例,其中 Margin 改为通过包含 Thickness 对象元素的属性元素语法进行设置。 新实例的四个关键属性设置为属性 Thickness

<Button Content="Click me">
    <Button.Margin>
        <Thickness Left="10" Top="20" Right="10" Bottom="30"/>
    </Button.Margin>
</Button>

注释

也有一些有限的对象,其中类型转换是将属性设置为该类型而不涉及子类的唯一公共方法,因为类型本身没有无参数构造函数。 示例为 Cursor

有关类型转换的详细信息,请参阅 TypeConverters 和 XAML

根元素和命名空间

XAML 文件必须只有一个根元素,才能同时是格式正确的 XML 文件和有效的 XAML 文件。 对于典型的 WPF 方案,可以使用 WPF 应用模型中具有重要意义的根元素(例如,WindowPage用于页面,ResourceDictionary用于外部字典,或Application用于应用定义)。 以下示例显示了 WPF 页面的典型 XAML 文件的根元素,其根元素为 Page.

<Page x:Class="index.Page1"
      xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
      Title="Page1">

</Page>

根元素还包含属性 xmlnsxmlns:x。 这些属性向 XAML 处理器指示哪些 XAML 命名空间包含标记将作为元素引用的后备类型的类型定义。 该 xmlns 属性专门指示默认 XAML 命名空间。 在默认 XAML 命名空间中,可以指定标记中的对象元素,而无需前缀。 对于大多数 WPF 应用方案,对于 SDK 的 WPF 部分给出的几乎所有示例,默认 XAML 命名空间将映射到 WPF 命名空间 http://schemas.microsoft.com/winfx/2006/xaml/presentation。 该 xmlns:x 属性指示附加的 XAML 命名空间,该命名空间映射 XAML 语言命名空间 http://schemas.microsoft.com/winfx/2006/xaml

使用xmlns来定义名称范围的使用和映射范围与 XML 1.0 规范一致。 XAML 名称范围与 XML 名称范围的不同之处在于,XAML 名称范围还涉及在解析和分析 XAML 时名称范围元素如何由类型支持。

这些 xmlns 属性仅在每个 XAML 文件的根元素上是必需的。 xmlns的定义将适用于根元素的所有子元素(这一行为与 XML 1.0 规范一致,例如xmlns)。xmlns的属性也允许在根元素下的其他元素上使用,并将应用于定义元素的任何子元素。 但是,XAML 命名空间的频繁定义或重新定义可能会导致难以读取的 XAML 标记样式。

其 XAML 处理器的 WPF 实现包含一个能够识别 WPF 核心程序集的基础结构。 已知 WPF 核心程序集包含支持 WPF 映射到默认 XAML 命名空间的类型。 这是通过项目生成文件和 WPF 生成和项目系统的一部分的配置启用的。 因此,只需将默认 XAML 命名空间声明为 xmlns,即可引用来自 WPF 程序集的 XAML 元素。

x: 前缀

在前面的根元素示例中,前缀 x: 用于映射 XAML 命名空间,该命名空间 http://schemas.microsoft.com/winfx/2006/xaml是支持 XAML 语言构造的专用 XAML 命名空间。 此 x: 前缀用于在整个 SDK 的项目模板、示例和文档中映射此 XAML 命名空间。 XAML 语言的 XAML 命名空间包含多个在 XAML 中经常使用的编程构造。 下面是将使用的最常见 x: 前缀编程构造的列表:

  • x:Key:为ResourceDictionary中的每个资源设置唯一键(或其他框架中的类似字典概念)。 x:Key 可能会构成你在典型的 WPF 应用标记中看到的 x: 使用情况的 90%。

  • x:Class:指定用于 XAML 页后台代码的类的 CLR 命名空间和类名。 必须要有这样的类以支持根据 WPF 编程模型的后置代码,因此几乎总能看到 x: 被映射,即使没有资源,情况也是如此。

  • x:Name:为处理对象元素后在运行时代码中存在的实例指定运行时对象名称。 一般情况下,通常会对 x:Name 使用 WPF 定义的等效属性。 此类属性专门映射到 CLR 支持属性,因此更方便应用编程,你经常使用运行时代码从初始化的 XAML 中查找命名元素。 最常见的此类属性是 FrameworkElement.Name。 当特定类型不支持等效的 WPF 框架级Name属性时,仍可能使用 x:Name。 这在某些动画场景中发生。

  • x:Static:启用一种引用,该引用返回一个不是 XAML 兼容属性的静态值。

  • x:Type:基于类型名称构造 Type 引用。 这用于指定采用 Type的属性,例如 Style.TargetType,尽管属性通常具有本机字符串到Type 转换,因此 x:Type 标记扩展用法是可选的。

前缀/XAML 命名空间中 x: 还有其他编程构造,这些构造并不常见。 有关详细信息,请参阅 XAML 命名空间 (x:) 语言功能

自定义前缀和自定义类型

对于你自己的自定义程序集,或者对于 PresentationCorePresentationFrameworkWindowsBase 的 WPF 核心之外的程序集,可以将程序集指定为自定义 xmlns 映射的一部分。 然后,可以在 XAML 中引用该程序集中的类型,只要正确实现该类型以支持尝试的 XAML 用法。

下面是自定义前缀在 XAML 标记中的工作方式的基本示例。 前缀 custom 在根元素标记中定义,并映射到打包并可用于应用的特定程序集。 此程序集包含一种类型 NumericUpDown,其实现旨在支持常规 XAML 用法,并使用允许在 WPF XAML 内容模型中特定位置插入的类继承。 此NumericUpDown控件实例声明为一个对象元素,并通过使用前缀使 XAML 分析器能识别哪个 XAML 命名空间包含该类型,从而确定包含类型定义的支持程序集的位置。

<Page
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:custom="clr-namespace:NumericUpDownCustomControl;assembly=CustomLibrary"
    >
  <StackPanel Name="LayoutRoot">
    <custom:NumericUpDown Name="numericCtrl1" Width="100" Height="60"/>
...
  </StackPanel>
</Page>

有关 XAML 中的自定义类型的详细信息,请参阅 适用于 WPF 的 XAML 和自定义类

有关程序集中的 XML 命名空间和代码命名空间如何相关的详细信息,请参阅 WPF XAML 的 XAML 命名空间和命名空间映射

事件和 XAML 代码后置

大多数 WPF 应用都由 XAML 标记和后台代码组成。 在项目中,XAML 将编写为 .xaml 文件,CLR 语言(如 Microsoft Visual Basic 或 C#)用于编写代码隐藏文件。 当 XAML 文件作为 WPF 编程和应用程序模型的一部分进行标记编译时,通过在 XAML 根元素中指定一个命名空间和类作为 x:Class 属性,来标识 XAML 文件中代码隐藏的文件的位置。

在到目前为止的示例中,你已看到多个按钮,但这些按钮中没有任何与它们关联的逻辑行为。 添加对象元素行为的主要应用程序级机制是使用元素类的现有事件,并为在运行时引发该事件时调用的该事件编写特定处理程序。 事件名称和要使用的处理程序名称在标记代码中指定,而实现处理程序的代码在后台代码中定义。

<Page x:Class="ExampleNamespace.ExamplePage"
      xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
    <StackPanel>
        <Button Click="Button_Click">Click me</Button>
    </StackPanel>
</Page>
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;

namespace ExampleNamespace;

public partial class ExamplePage : Page
{
    public ExamplePage() =>
        InitializeComponent();

    private void Button_Click(object sender, RoutedEventArgs e)
    {
        var buttonControl = (Button)e.Source;
        buttonControl.Foreground = Brushes.Red;
    }
}
Class ExamplePage
    Private Sub Button_Click(sender As Object, e As RoutedEventArgs)
        Dim buttonControl = DirectCast(e.Source, Button)
        buttonControl.Foreground = Brushes.Red
    End Sub
End Class

请注意,代码隐藏文件使用 CLR 命名空间 ExampleNamespace (命名空间在 Visual Basic 中不可见),并声明 ExamplePage 为该命名空间中的分部类。 这与x:ClassExampleNamespace属性值并行。 ExamplePage 已在标记根目录中提供。 WPF 标记编译器将通过从根元素类型派生类,为任何已编译的 XAML 文件创建分部类。 当您提供也定义同一分部类的后台代码时,生成的代码会合并到已编译应用程序的相同命名空间和类中。

重要

在 Visual Basic 中,XAML 和后台代码都隐含有根命名空间。 只有嵌套命名空间可见。 本文演示 C# 项目的 XAML。

有关 WPF 中代码隐藏编程的要求的详细信息,请参阅 WPF 中的代码隐藏、事件处理程序和分部类要求

如果不想创建单独的代码隐藏文件,还可以在 XAML 文件中内联代码。 但是,内联代码是一种不太通用的技术,具有实质性的限制。 有关详细信息,请参阅 WPF 中的Code-Behind 和 XAML

路由事件

WPF 的基础特定事件功能是路由事件。 路由事件使元素能够处理由不同元素引发的事件,只要元素通过树关系进行连接。 使用 XAML 属性指定事件处理时,可以在任何元素上侦听和处理路由事件,包括不列出类成员表中特定事件的元素。 这是通过限定具有拥有类名的事件名称属性来实现的。 例如,在正在进行的StackPanel / Button示例中,父元素StackPanel可以通过在对象元素StackPanel上指定属性Button.Click,将处理程序名称作为该属性值,以便为子元素按钮的Click事件注册处理程序。 有关详细信息,请参阅 路由事件概述

已命名元素

默认情况下,通过处理 XAML 对象元素在对象图中创建的对象实例没有唯一标识符或对象引用。 相比之下,如果在代码中调用构造函数,则几乎总是使用构造函数结果将变量设置为构造的实例,以便稍后可以在代码中引用该实例。 为了提供对通过标记定义创建的对象的标准化访问,XAML 定义 x:Name 属性。 可以在任何对象元素上设置特性的值 x:Name 。 在后台代码中,您选择的标识符相当于引用构造实例的实例变量。 在所有方面,命名元素的功能如同对象实例(名称引用该实例),后台代码可以引用命名元素用于在应用中处理运行时交互。 实例和变量之间的这种连接是由 WPF XAML 标记编译器完成的,更具体地说,涉及的功能和模式,如 InitializeComponent 本文中不会详细讨论这些特性和模式。

WPF 框架级 XAML 元素继承一个 Name 属性,该属性等效于 XAML 定义的 x:Name 属性。 某些其他类还提供属性级别的等效项 x:Name,这通常也定义为 Name 属性。 一般来说,如果在所选元素/类型的成员表中找不到 Name 属性,请改用 x:Name 。 这些 x:Name 值将为可在运行时使用的 XAML 元素提供标识符,这些元素可由特定子系统或实用工具方法(例如 FindName) 使用。

以下示例将Name设置在StackPanel元素上。 然后, StackPanel内部的Button处理程序根据Name的设置通过其实例buttonContainer引用StackPanel

<StackPanel Name="buttonContainer">
    <Button Click="RemoveThis_Click">Click to remove this button</Button>
</StackPanel>
private void RemoveThis_Click(object sender, RoutedEventArgs e)
{
    var element = (FrameworkElement)e.Source;
    
    if (buttonContainer.Children.Contains(element))
        buttonContainer.Children.Remove(element);
}
Private Sub RemoveThis_Click(sender As Object, e As RoutedEventArgs)
    Dim element = DirectCast(e.Source, FrameworkElement)

    If buttonContainer.Children.Contains(element) Then
        buttonContainer.Children.Remove(element)
    End If
End Sub

与变量一样,实例的 XAML 名称受范围概念的约束,以便可以强制名称在可预测的某个范围内是唯一的。 定义页面的主标记表示一个唯一的 XAML 名称范围,XAML 名称范围边界是该页的根元素。 但是,其他标记源可以在运行时与页面交互,例如样式中的样式或模板,并且此类标记源通常具有自己的 XAML 名称范围,这些名称范围不一定与页面的 XAML 名称范围连接。 有关 x:Name XAML 名称范围的详细信息,请参阅 Namex:Name 指令WPF XAML 名称范围

附加属性和附加事件

XAML 指定一种语言功能,允许在任何元素上指定某些属性或事件,即使属性或事件不存在于要设置的元素的类型定义中也是如此。 此功能的属性版本称为附加属性,事件版本称为附加事件。 从概念上讲,可以将附加属性和附加事件视为可在任何 XAML 元素/对象实例上设置的全局成员。 但是,该元素/类或更大的基础结构必须支持绑定值的支持属性存储。

XAML 中的附加属性通常通过属性语法使用。 在属性语法中,可以在窗体 ownerType.propertyName中指定附加属性。

从表面上看,这类似于属性元素用法,但在这种情况下, ownerType 指定的类型始终与设置附加属性的对象元素不同。 ownerType 是提供 XAML 处理器获取或设置附加属性值所需的访问器方法的类型。

附加属性的最常见方案是使子元素能够向其父元素报告属性值。

下面的示例说明了附加属性DockPanel.Dock。 该 DockPanel 类定义访问器 DockPanel.Dock 并拥有附加属性。 该 DockPanel 类还包括遍历其子元素的逻辑,并专门检查每个元素的设定值 DockPanel.Dock。 如果找到值,则该值在布局期间用于定位子元素。 使用DockPanel.Dock附加属性和此定位功能,实际上是DockPanel类的动机场景。

<DockPanel>
    <Button DockPanel.Dock="Left" Width="100" Height="20">I am on the left</Button>
    <Button DockPanel.Dock="Right" Width="100" Height="20">I am on the right</Button>
</DockPanel>

在 WPF 中,大多数或所有附加属性也作为依赖属性实现。 有关详细信息,请参阅 附加属性概述

附加事件使用类似 ownerType.eventName 形式的属性语法。 与非附加事件一样,XAML 中附加事件的属性值指定在元素上处理事件时调用的处理程序方法的名称。 WPF XAML 中的附加事件用法不太常见。 有关详细信息,请参阅 附加事件概述

基类型

基础 WPF XAML 及其 XAML 命名空间是对应于 XAML 的 CLR 对象和标记元素的类型集合。 但是,并非所有类都可以映射到元素。 抽象类(如 ButtonBase某些非抽象基类)用于 CLR 对象模型中的继承。 基类(包括抽象类)对于 XAML 开发仍然很重要,因为每个具体 XAML 元素都从其层次结构中的某些基类继承成员。 通常,这些成员包括可以设置为元素属性的特性或可以处理的事件。 FrameworkElement 是 WPF 框架级别的 WPF 的具体基 UI 类。 设计 UI 时,将使用各种形状、面板、修饰器或控件类,这些类都派生自 FrameworkElement。 相关基类FrameworkContentElement支持文档导向的元素,这些元素适用于流式布局展示,且这些API有意模仿FrameworkElement中的API。 元素级别和 CLR 对象模型的属性组合提供了一组可在大多数具体 XAML 元素上设置的通用属性,而不考虑特定的 XAML 元素及其基础类型。

安全

XAML 是一种直接表示对象实例化和执行的标记语言。 这就是为什么在 XAML 中创建的元素能够与系统资源(例如网络访问、文件系统 IO 等)进行交互,就像应用代码一样。 XAML 对系统资源的访问权限与托管应用的访问权限也相同。

WPF 中的代码访问安全性 (CAS)

与 .NET Framework 不同,适用于 .NET 的 WPF 不支持 CAS。 有关详细信息,请参阅 代码访问安全性差异

从代码加载 XAML

XAML 可用于定义所有 UI,但有时还适合在 XAML 中仅定义 UI 的一部分。 此功能可用于:

  • 启用部分自定义。
  • UI 信息的本地存储。
  • 为业务对象建模。

这些方案的关键是 XamlReader 类及其 Load 方法。 输入是一个 XAML 文件,输出是一个对象,表示从该标记创建的所有对象的运行时树。 然后,你可以将对象作为属性插入到应用中已存在的另一个对象里。 只要该属性位于内容模型中并且具有显示功能来通知执行引擎已将新内容添加到应用中,就可以通过动态加载 XAML 轻松修改正在运行的应用的内容。

另请参阅