附加属性在 WPF 中究竟是如何工作的?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1173494/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-08 20:45:46  来源:igfitidea点击:

How exactly do Attached Properties work in WPF?

wpfxamlattached-properties

提问by Mark Carpenter

I'm a bit mystified as to how Attached Properties actually convey their values to either parent or child elements. TextElement.FontFamilycauses child elements to inherit the value assigned to that property (a seemingly downstream operation, parent to child). Grid.Columncauses a parent item to display that child in a particular position (a seemingly upstream operation, child to parent). How do Attached Property values know to either flow up or down? Is my conception of this incorrect, or is there a piece missing that will put all of this into perspective?

我对附加属性如何实际将它们的值传达给父元素或子元素感到有些困惑。TextElement.FontFamily导致子元素继承分配给该属性的值(看似下游的操作,父对子)。Grid.Column导致父项在特定位置显示该子项(看似上游的操作,子项到父项)。附加属性值如何知道是向上流动还是向下流动?我对此的看法是不正确的,还是缺少一部分可以使所有这些都变得正确?

<StackPanel TextElement.FontFamily="Wingdings">
    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="*"/>
            <ColumnDefinition Width="*"/>
        </Grid.ColumnDefinitions>

        <Button Grid.Column="1" Content="My Button"/>
    </Grid>
</StackPanel>

回答by Kenan E. K.

There are two concepts here: dependency propertiesand attached dependency properties. "Attached Properties" are dependency properties, and as such support dependency property value inheritance.

这里有两个概念:依赖属性附加依赖属性。“附加属性”是依赖属性,因此支持依赖属性值继承

About basic dependency properties, a very rough statement would be that they basically inherit their values from parent elements in the wpf (logical/visual) tree. A dependency property (attached or not) inherits its value "downwards" if its metadatais set with the FrameworkPropertyMetadataOptions.Inheritflag, and in many cases this is so.

关于基本的依赖属性,一个非常粗略的说法是它们基本上从 wpf(逻辑/视觉)树中的父元素继承它们的值。如果使用FrameworkPropertyMetadataOptions设置其元数据,则依赖属性(附加或不附加)将“向下”继承其值。继承标志,在很多情况下就是这样。

Attached properties are properties which can be set on any wpf object (basically, at leasta DependencyObject) via the DependencyObject.SetValuemethod. The purpose for this mechanism is to "attach" to other objects information needed by parent objects, not the child objects themselves. For example, the Grid.Rowis an attached property required by the Grid to place items within its render area.

附加属性是可以通过DependencyObject.SetValue方法在任何 wpf 对象(基本上,至少是一个 DependencyObject)上设置的属性。此机制的目的是将父对象所需的信息“附加”到其他对象,而不是子对象本身。例如,Grid.Row是 Grid 在其渲染区域内放置项目所需的附加属性。

Dependency properties are inherited "downwards" automatically by the wpf object system.

依赖属性由 wpf 对象系统自动“向下”继承。

Attached properties are examined "upwards" explicitly, in the code of specific objects. In the case of Grid, upon determining where to place its items, it checks for the value of Grid.Row and Grid.Column attached properties on each contained item.

在特定对象的代码中,显式地“向上”检查附加属性。在 Grid 的情况下,在确定放置其项目的位置后,它会检查每个包含项目的 Grid.Row 和 Grid.Column 附加属性的值。

It is also often the technique to create custom attached properties which modify in some way the objects they are attached to (for example, the Drag'n'Drop functionality via attached properties).

它通常也是创建自定义附加属性的技术,这些属性以某种方式修改它们附加到的对象(例如,通过附加属性拖放功能)。

As an additional note, a good example of an inheriting attached property is TextElement.FontFamily. Grid.Row and Grid.Column properties do not have the Inherits flag set.

作为附加说明,继承附加属性的一个很好的例子是TextElement.FontFamily。Grid.Row 和 Grid.Column 属性没有设置 Inherits 标志。

TextElement.FontFamily, from Reflector:

TextElement.FontFamily,来自 Reflector:

 FontFamilyProperty = DependencyProperty.RegisterAttached("FontFamily", typeof(FontFamily), typeof(TextElement), new FrameworkPropertyMetadata(SystemFonts.MessageFontFamily, FrameworkPropertyMetadataOptions.Inherits | FrameworkPropertyMetadataOptions.AffectsRender | FrameworkPropertyMetadataOptions.AffectsMeasure), new ValidateValueCallback(TextElement.IsValidFontFamily));

Grid.Row, from Reflector:

Grid.Row,来自反射器:

 RowProperty = DependencyProperty.RegisterAttached("Row", typeof(int), typeof(Grid), new FrameworkPropertyMetadata(0, new PropertyChangedCallback(Grid.OnCellAttachedPropertyChanged)), new ValidateValueCallback(Grid.IsIntValueNotNegative));

回答by Charlie

From MSDN:

MSDN

Although attached properties are settable on any object, that does not automatically mean that setting the property will produce a tangible result, or that the value will ever be used by another object. Generally, attached properties are intended so that objects coming from a wide variety of possible class hierarchies or logical relationships can each report common information to the type that defines the attached property. The type that defines the attached property typically follows one of these models:

尽管附加属性可在任何对象上设置,但这并不自动意味着设置该属性会产生有形的结果,或者该值将永远被另一个对象使用。通常,附加属性的目的是使来自各种可能的类层次结构或逻辑关系的对象都可以向定义附加属性的类型报告公共信息。定义附加属性的类型通常遵循以下模型之一:

  • The type that defines the attached property is designed so that it can be the parent element of the elements that will set values for the attached property. The type then iterates its child objects through internal logic against some object tree structure, obtains the values, and acts on those values in some manner.

  • The type that defines the attached property will be used as the child element for a variety of possible parent elements and content models.

  • The type that defines the attached property represents a service. Other types set values for the attached property. Then, when the element that set the property is evaluated in the context of the service, the attached property values are obtained through internal logic of the service class.

  • 定义附加属性的类型被设计为可以成为为附加属性设置值的元素的父元素。然后该类型通过内部逻辑针对某个对象树结构迭代其子对象,获取值,并以某种方式对这些值进行操作。

  • 定义附加属性的类型将用作各种可能的父元素和内容模型的子元素。

  • 定义附加属性的类型表示服务。其他类型为附加属性设置值。然后,当在服务的上下文中评估设置属性的元素时,通过服务类的内部逻辑获取附加的属性值。

An Example of a Parent-Defined Attached Property

父级定义的附加属性示例

The most typical scenario where WPF defines an attached property is when a parent element supports a child element collection, and also implements a behavior where the specifics of the behavior are reported individually for each child element.

WPF 定义附加属性的最典型场景是父元素支持子元素集合,并且还实现了一种行为,其中为每个子元素单独报告行为的细节。

DockPanel defines the DockPanel.Dock attached property, and DockPanel has class-level code as part of its rendering logic (specifically, MeasureOverride and ArrangeOverride). A DockPanel instance will always check to see whether any of its immediate child elements have set a value for DockPanel.Dock. If so, those values become input for the rendering logic applied to that particular child element. Nested DockPanel instances each treat their own immediate child element collections, but that behavior is implementation-specific to how DockPanel processes DockPanel.Dock values. It is theoretically possible to have attached properties that influence elements beyond the immediate parent. If the DockPanel.Dock attached property is set on an element that has no DockPanel parent element to act upon it, no error or exception is raised. This simply means that a global property value was set, but it has no current DockPanel parent that could consume the information.

DockPanel 定义了 DockPanel.Dock 附加属性,并且 DockPanel 将类级代码作为其呈现逻辑的一部分(特别是 MeasureOverride 和ArrangeOverride)。DockPanel 实例将始终检查它的任何直接子元素是否为 DockPanel.Dock 设置了值。如果是这样,这些值将成为应用于该特定子元素的呈现逻辑的输入。嵌套的 DockPanel 实例每个都处理它们自己的直接子元素集合,但该行为特定于 DockPanel 如何处理 DockPanel.Dock 值的实现。理论上有可能具有影响直接父级之外的元素的附加属性。如果 DockPanel.Dock 附加属性设置在没有 DockPanel 父元素对其进行操作的元素上,则不会引发错误或异常。

回答by Carlo

In simple words this is how I understand it (please correct me if I'm wrong).

简单来说,这就是我的理解(如果我错了,请纠正我)。

An object (A) implements a property that will attach to another object (B) (object B doesn't even know about the existence of this "attachable" property). Object B needs to inherit from DependencyObject.

一个对象 (A) 实现了一个将附加到另一个对象 (B) 的属性(对象 B 甚至不知道这个“可附加”属性的存在)。对象 B 需要从 DependencyObject 继承。

Object A also implements a static method to check for it's "attachable" property in other objects, A.GetAttachedProperty(B).

对象 A 还实现了一个静态方法来检查它在其他对象中的“可附加”属性,即 A.GetAttachedProperty(B)。

If B has the attached property from A, A.GetAttachedProperty will read and return it's value. Otherwise A will try to read it, and return null since it's not there.

如果 B 具有来自 A 的附加属性,则 A.GetAttachedProperty 将读取并返回它的值。否则 A 将尝试读取它,并返回 null 因为它不存在。