附加属性概述

附加属性是一个 XAML 概念。 附加属性允许在对象上设置其他属性/值对,但属性不是原始对象定义的一部分。 附加属性通常定义为依赖属性的专用形式,该依赖属性在所有者类型的对象模型中没有传统的属性包装器。

先决条件

我们假设你了解依赖项属性的基本概念,并具有读取 依赖项属性概述

XAML 中的附加属性

在 XAML 中,使用语法 AttachedPropertyProvider.PropertyName 设置附加属性。 下面是如何在 XAML 中设置 Canvas.Left 的示例。

<Canvas>
  <Button Canvas.Left="50">Hello</Button>
</Canvas>

注意

我们仅将 Canvas.Left 用作示例附加属性,而不完全介绍使用它的原因。 若要详细了解 Canvas.Left 的用途以及 Canvas 如何处理其布局子级,请参阅 Canvas 参考主题或使用 XAML 定义布局。

为何使用附加属性?

附加属性是转义编码约定的一种方法,这些约定可能会阻止关系中的不同对象在运行时相互通信。 当然,可以将属性放在通用基类上,以便每个对象只能获取和设置该属性。 但最终,你可能想要执行此操作的场景数量将膨胀到具有可共享属性的基类。 它甚至可能会引入可能只有两百个后代试图使用属性的情况。 这不是很好的类设计。 为了解决此问题,附加属性概念使对象能够为其自己的类结构未定义的属性赋值。 定义类可以在对象树中创建各种对象后,在运行时从子对象读取值。

例如,子元素可以使用附加属性来告知其父元素如何在 UI 中显示它们。 这是 Canvas.Left 附加属性的情况 Canvas.Left 创建为附加属性,因为它在 Canvas 元素中包含的元素上设置,而不是在 Canvas 本身上设置。 然后,任何可能的子元素都使用 Canvas.LeftCanvas.Top 在 Canvas 布局容器父元素中指定其布局偏移量。 通过附加属性,无需将基元素的对象模型与许多可能布局容器中的一个应用的大量属性混杂在一起即可实现此目的。 相反,许多布局容器实现其自己的附加属性集。

为了实现附加属性,Canvas 类定义名为 Canvas.LeftProperty 的静态 DependencyProperty 字段。 然后,Canvas 提供 SetLeft 和 GetLeft 方法作为附加属性的公共访问器,以启用 XAML 设置和运行时值访问。 对于 XAML 和依赖属性系统,这组 API 满足一种模式,该模式为附加属性启用特定的 XAML 语法,并将值存储在依赖属性存储中。

拥有类型如何使用附加属性

尽管可以在任何 XAML 元素(或任何基础 DependencyObject)上设置附加属性,但这并不意味着设置该属性会产生一个有形的结果,或者访问该值。 定义附加属性的类型通常遵循以下方案之一:

  • 定义附加属性的类型是其他对象关系的父级。 子对象将设置附加属性的值。 附加属性所有者类型具有一些先天行为,这些行为循环访问其子元素、获取值,并在对象生存期中的某个时间点对这些值执行操作(布局操作、 SizeChanged 等)。
  • 定义附加属性的类型用作各种可能的父元素和 con帐篷模式ls 的子元素,但信息不一定是布局信息。
  • 附加属性将信息报告给服务,而不是向另一个 UI 元素报告信息。

有关这些方案和拥有类型的详细信息,请参阅自定义附加属性“Canvas.Left”部分。

代码中的附加属性

附加属性没有典型的属性包装器,因此可以轻松获取和设置访问权限,就像其他依赖属性一样。 这是因为附加属性不一定是设置属性的实例的代码中心对象模型的一部分。 (虽然不常见,但允许定义一个属性,该属性既是附加属性,其他类型可以自行设置,而且在拥有类型上也有传统的属性用法。

可通过两种方法在代码中设置附加属性:使用属性系统 API 或使用 XAML 模式访问器。 这些技术在最终结果方面几乎等效,因此使用哪种技术主要是编码样式的问题。

使用属性系统

Windows 运行时的附加属性实现为依赖属性,以便这些值可以存储在属性系统的共享依赖属性存储中。 因此,附加属性在拥有类上公开依赖属性标识符。

若要在代码中设置附加属性,请调用 SetValue 方法,并传递 DependencyProperty 字段,该字段充当该附加属性的标识符。 (还传递要设置的值。

若要获取代码中附加属性的值,请调用 GetValue 方法,再次传递用作标识符的 DependencyProperty 字段。

使用 XAML 访问器模式

当 XAML 分析到对象树中时,XAML 处理器必须能够设置附加属性值。 附加属性的所有者类型必须实现以 GetPropertyNameSetPropertyName 形式命名的专用访问器方法。 这些专用访问器方法也是在代码中获取或设置附加属性的一种方法。 从代码的角度来看,附加属性类似于具有方法访问器而不是属性访问器的后盾字段,并且支持字段可以存在于任何对象上,而无需专门定义。

下一个示例演示如何通过 XAML 访问器 API 在代码中设置附加属性。 在此示例中,myCheckBox是 CheckBox 类的一个实例。 最后一行是实际设置值的代码;前面刚建立实例及其父子关系的行。 如果使用属性系统,则未注释的最后一行是语法。 如果使用 XAML 访问器模式,则注释的最后一行是语法。

    Canvas myC = new Canvas();
    CheckBox myCheckBox = new CheckBox();
    myCheckBox.Content = "Hello";
    myC.Children.Add(myCheckBox);
    myCheckBox.SetValue(Canvas.TopProperty,75);
    //Canvas.SetTop(myCheckBox, 75);
    Dim myC As Canvas = New Canvas()
    Dim myCheckBox As CheckBox= New CheckBox()
    myCheckBox.Content = "Hello"
    myC.Children.Add(myCheckBox)
    myCheckBox.SetValue(Canvas.TopProperty,75)
    ' Canvas.SetTop(myCheckBox, 75)
Canvas myC;
CheckBox myCheckBox;
myCheckBox.Content(winrt::box_value(L"Hello"));
myC.Children().Append(myCheckBox);
myCheckBox.SetValue(Canvas::TopProperty(), winrt::box_value(75));
// Canvas::SetTop(myCheckBox, 75);
    Canvas^ myC = ref new Canvas();
    CheckBox^ myCheckBox = ref new CheckBox();
    myCheckBox->Content="Hello";
    myC->Children->Append(myCheckBox);
    myCheckBox->SetValue(Canvas::TopProperty,75);
    // Canvas::SetTop(myCheckBox, 75);

自定义附加属性

有关如何定义自定义附加属性的代码示例,以及有关使用附加属性的方案的详细信息,请参阅 自定义附加属性

附加属性引用的特殊语法

附加属性名称中的点是标识模式的关键部分。 当语法或情况将点视为具有其他含义时,有时存在歧义。 例如,将点视为绑定路径的对象模型遍历。 在大多数情况下,涉及此类歧义,附加属性有一种特殊的语法,使内部点仍可解析为所有者附加属性的属性分隔符。

  • 若要将附加属性指定为动画的目标路径的一部分,请将附加的属性名称括在括号(“()”中,例如“(Canvas.Left)”。 有关详细信息,请参阅 Property-path 语法

警告

Windows 运行时 XAML 实现的现有局限性是无法创建自定义附加属性的动画。

  • 若要将附加属性指定为从一个资源文件到 x:Uid 的资源引用的目标属性,可以使用一种特殊语法,即将代码样式的完全限定的 using: 声明放在方括号(“[]”)内,以创建一种专门的领域分隔效果。 例如,假设存在一个元素“<TextBlock x:Uid="Title" />”,资源文件中定位该实例上 Canvas.Top 值的资源键是“Title.[using:Windows.UI.Xaml.Controls]Canvas.Top”。 有关资源文件和 XAML 的详细信息,请参阅 快速入门:翻译 UI 资源