附加属性概述Attached properties overview

附加属性是一种 XAML 概念。An attached property is a XAML concept. 使用附加属性,可以在对象上设置其他属性/值对,但这些属性并不是原始对象定义的组成部分。Attached properties enable additional property/value pairs to be set on an object, but the properties are not part of the original object definition. 附加属性通常定义为一种专门形式的依赖属性,在所有者类型的对象模型中没有传统的属性包装器。Attached properties are typically defined as a specialized form of dependency property that doesn't have a conventional property wrapper in the owner type's object model.

先决条件Prerequisites

我们假设你理解依赖属性的基本概念,并且已阅读依赖属性概述We assume that you understand the basic concept of dependency properties, and have read Dependency properties overview.

XAML 中的附加属性Attached properties in XAML

在 XAML 中,可使用语法 AttachedPropertyProvider.PropertyName 设置附加属性。In XAML, you set attached properties by using the syntax AttachedPropertyProvider.PropertyName. 以下是如何在 XAML 中设置 Canvas.Left 的一个示例。Here is an example of how you can set Canvas.Left in XAML.

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

备注

我们仅用 Canvas.Left 而无需完全解释为什么要使用的一个示例附加属性。We're just using Canvas.Left as an example attached property without fully explaining why you'd use it. 如果你希望了解有关 Canvas.Left 的目的以及 Canvas 如何处理其布局子项的详细信息,请参阅 Canvas 参考主题或使用 XAML 定义布局If you want to know more about what Canvas.Left is for and how Canvas handles its layout children, see the Canvas reference topic or Define layouts with XAML.

为什么使用附加属性?Why use attached properties?

使用附加属性,可以避开可能会防止一个关系中的不同对象在运行时相互传递信息的编码约定。Attached properties are a way to escape the coding conventions that might prevent different objects in a relationship from communicating information to each other at run time. 一定可以针对常见的基类设置属性,以便每个对象只需获取和设置该属性即可。It's certainly possible to put properties on a common base class so that each object could just get and set that property. 但是,你可能希望在很多情况下这样做,这会使你的基类最终充斥着大量可共享的属性。But eventually the sheer number of scenarios where you might want to do this will bloat your base classes with shareable properties. 它甚至可能会引入以下情况:在数百个后代中,只有两个后代尝试使用一个属性。It might even introduce cases where there might just be two of hundreds of descendants trying to use a property. 这样的类设计很糟糕。That's not good class design. 为了解决此问题,我们使用附加属性概念来允许对象为不是由它自己的类结构定义的属性赋值。To address this, the attached property concept enables an object to assign a value for a property that its own class structure doesn't define. 在对象树中完成创建各个对象之后,定义类可以在运行时从子对象中读取此值。The defining class can read the value from child objects at run time after the various objects are created in an object tree.

例如,子元素可使用附加属性通知父元素它们如何在 UI 中显示。For example, child elements can use attached properties to inform their parent element of how they are to be presented in the UI. Canvas.Left 附加属性就属于此情况。This is the case with the Canvas.Left attached property. Canvas.Left 创建为一个附加属性,因为它在 Canvas 元素内包含的元素上设置,而不是在 Canvas 本身上设置。Canvas.Left is created as an attached property because it is set on elements that are contained within a Canvas element, rather than on the Canvas itself. 然后,任何可能的子元素使用 Canvas.LeftCanvas.TopCanvas 布局容器父元素中指定它的布局偏移。Any possible child element then uses Canvas.Left and Canvas.Top to specify its layout offset within the Canvas layout container parent. 附加属性使这一场景的实现成为可能,而无需将基础元素的对象模型与大量属性聚集在一起,并且每个属性仅应用于许多可能的布局容器中的一种。Attached properties make it possible for this to work without cluttering the base element's object model with lots of properties that each apply to only one of the many possible layout containers. 相反,许多布局容器实现它们自己的附加属性集。Instead, many of the layout containers implement their own attached property set.

为了实现附加属性,Canvas 类定义一个名为 Canvas.LeftProperty 的静态 DependencyProperty 字段。To implement the attached property, the Canvas class defines a static DependencyProperty field named Canvas.LeftProperty. 然后,Canvas 提供 SetLeftGetLeft 方法作为附加属性的公共访问器,以同时支持 XAML 设置和运行时值访问。Then, Canvas provides the SetLeft and GetLeft methods as public accessors for the attached property, to enable both XAML setting and run-time value access. 对于 XAML 和依赖属性系统,这组 API 实现了一种模式,支持为附加属性使用特定的 XAML 语法并将值存储在依赖属性存储中。For XAML and for the dependency property system, this set of APIs satisfies a pattern that enables a specific XAML syntax for attached properties, and stores the value in the dependency property store.

拥有类型如何使用附加属性How the owning type uses attached properties

尽管附加属性可在任何 XAML 元素(或任何基础 DependencyObject)上设置,但这不会自动表明设置该属性将生成实际的结果,或者该值将会被访问。Although attached properties can be set on any XAML element (or any underlying DependencyObject), that doesn't automatically mean that setting the property produces a tangible result, or that the value is ever accessed. 定义附加属性的类型通常采用下列方案之一:The type that defines the attached property typically follows one of these scenarios:

  • 用来定义附加属性的类型在与其他对象的关系中作为父对象。The type that defines the attached property is the parent in a relationship of other objects. 子对象将为附加属性设置值。The child objects will set values for the attached property. 附加属性的所有者类型具有一些固有的行为,该行为循环访问附加属性的子元素、获取它们的值并在对象生存期的某个时间点对这些值执行操作(布局操作、SizeChanged 等)。The attached property owner type has some innate behavior that iterates through its child elements, obtains the values, and acts on those values at some point in object lifetime (a layout action, SizeChanged, etc.)
  • 定义附加属性的类型用作各种可能的父元素和内容模型的子元素,但是此信息不一定是布局信息。The type that defines the attached property is used as the child element for a variety of possible parent elements and content models, but the info isn't necessarily layout info.
  • 附加属性向一个服务(而不是另一个 UI 元素)报告信息。The attached property reports info to a service, not to another UI element.

有关这些方案和拥有类型的详细信息,请参阅自定义的附加属性的“有关 Canvas.Left 的详细信息”部分。For more info on these scenarios and owning types, see the "More about Canvas.Left" section of Custom attached properties.

代码中的附加属性Attached properties in code

与其他依赖属性不同,附加属性没有典型的属性包装器用于简化获取和设置访问。Attached properties don't have the typical property wrappers for easy get and set access like other dependency properties do. 这是因为附加属性不一定是设置属性的实例的以代码为中心的对象模型。This is because the attached property is not necessarily part of the code-centered object model for instances where the property is set. (允许[但不常用]定义这样一个属性,它既是其他类型可在自身上设置的附加属性,也在拥有类型上有一种方便的属性用法。)(It is permissible, though uncommon, to define a property that is both an attached property that other types can set on themselves, and that also has a conventional property usage on the owning type.)

有两种在代码中设置附加属性的方式:使用属性系统 API 或使用 XAML 模式访问器。There are two ways to set an attached property in code: use the property-system APIs, or use the XAML pattern accessors. 这些技术的最终结果大体相同,所以决定使用哪种技术主要在于编码风格。These techniques are pretty much equivalent in terms of their end result, so which one to use is mostly a matter of coding style.

使用属性系统Using the property system

Windows 运行时的附加属性实现为依赖属性,以便这些值可以由属性系统存储在共享依赖属性存储中。Attached properties for the Windows Runtime are implemented as dependency properties, so that the values can be stored in the shared dependency-property store by the property system. 因此附加属性在拥有类上公开一个依赖属性标识符。Therefore attached properties expose a dependency property identifier on the owning class.

若要在代码中设置附加属性,你可以调用 SetValue 方法,传递用作该附加属性标识符的 DependencyProperty 字段。To set an attached property in code, you call the SetValue method, and pass the DependencyProperty field that serves as the identifier for that attached property. (还需传递要设置的值。)(You also pass the value to set.)

若要在代码中获得附加属性的值,你可以调用 GetValue 方法,再次传递用作标识符的 DependencyProperty 字段。To get the value of an attached property in code, you call the GetValue method, again passing the DependencyProperty field that serves as the identifier.

使用 XAML 访问器模式Using the XAML accessor pattern

XAML 处理器必须能够在将 XAML 分析为对象树时设置附加属性值。A XAML processor must be able to set attached property values when XAML is parsed into an object tree. 附加属性的所有者类型必须以 GetPropertyNameSetPropertyName 的形式实现专用的访问器方法。The owner type of the attached property must implement dedicated accessor methods named in the form GetPropertyName and SetPropertyName. 这些专用的访问器方法也是一种在代码中获取或设置附加属性的方式。These dedicated accessor methods are also one way to get or set the attached property in code. 从代码角度讲,附加属性类似于拥有方法访问器而不是属性访问器的支持字段,并且该支持字段可存在于任何对象上,而不需要专门定义。From a code perspective, an attached property is similar to a backing field that has method accessors instead of property accessors, and that backing field can exist on any object rather than having to be specifically defined.

下面的示例展示了如何通过 XAML 访问器 API 在代码中设置附加属性。The next example shows how you can set an attached property in code via the XAML accessor API. 在此示例中,myCheckBoxCheckBox 类的一个实例。In this example, myCheckBox is an instance of the CheckBox class. 最后一行是实际设置值的代码,该行之前的行只是建立实例及其父子关系。The last line is the code that actually sets the value; the lines before that just establish the instances and their parent-child relationship. 未注释掉的最后一行是使用属性系统的语法。The uncommented last line is the syntax if you use the property system. 注释掉的最后一行是使用 XAML 访问器模式的语法。The commented last line is the syntax if you use the XAML accessor pattern.

    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);

自定义附加属性Custom attached properties

有关定义自定义附加属性的代码示例,以及有关使用附加属性的场景的详细信息,请参阅自定义附加属性For code examples of how to define custom attached properties, and more info about the scenarios for using an attached property, see Custom attached properties.

附加属性引用的特殊语法Special syntax for attached property references

附加属性名称中的点是标识模式的一个关键部分。The dot in an attached property name is a key part of the identification pattern. 在某种语法或情况认为点拥有其他某种含义时,就会导致多义性。Sometimes there are ambiguities when a syntax or situation treats the dot as having some other meaning. 例如,一个点可视为对绑定路径的对象模型遍历。For example, a dot is treated as an object-model traversal for a binding path. 在大部分涉及这种歧义性的情况下,附加属性有一种特殊语法,使内部点仍被分析为附加属性的 owner . property 分隔符。In most cases involving such ambiguity, there is a special syntax for an attached property that enables the inner dot still to be parsed as the owner.property separator of an attached property.

  • 若要将一个附加属性指定为动画目标路径的一部分,可以将附加属性名称放在圆括号(“()”)中,例如“(Canvas.Left)”。To specify an attached property as part of a target path for an animation, enclose the attached property name in parentheses ("()")—for example, "(Canvas.Left)". 有关详细信息,请参阅 Property-path 语法For more info, see Property-path syntax.

警告

Windows 运行时 XAML 实现现有限制是,不能对自定义附加的属性进行动画处理。An existing limitation of the Windows Runtime XAML implementation is that you cannot animate a custom attached property.

  • 若要指定作为到资源文件中的资源引用的目标属性的附加的属性X:uid,使用注入代码样式,完全限定的特殊语法使用: 内的声明方括号 ("[]"),以创建一个故意安排的作用域分行符。To specify an attached property as the target property for a resource reference from a resource file to x:Uid, use a special syntax that injects a code-style, fully qualified using: declaration inside square brackets ("[]"), to create a deliberate scope break. 例如,假设存在一个元素<TextBlock x:Uid="Title" />,在目标资源文件中的资源键Canvas.Top在该实例上的值是"标题。[using:Windows.UI.Xaml.Controls]Canvas.Top"。For example, assuming there exists an element <TextBlock x:Uid="Title" />, the resource key in the resource file that targets the Canvas.Top value on that instance is "Title.[using:Windows.UI.Xaml.Controls]Canvas.Top". 资源文件和 XAML 的详细信息,请参阅快速入门:将 UI 资源翻译For more info on resource files and XAML, see Quickstart: Translating UI resources.