26

对于附加属性如何将它们的值实际传递给父元素或子元素,我感到有些困惑。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>
4

3 回答 3

46

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

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

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

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

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

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

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

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,来自 Reflector:

RowProperty = DependencyProperty.RegisterAttached("Row", typeof(int), typeof(Grid), new FrameworkPropertyMetadata(0, new PropertyChangedCallback(Grid.OnCellAttachedPropertyChanged)), new ValidateValueCallback(Grid.IsIntValueNotNegative));
于 2009-07-23T20:19:32.143 回答
2

来自MSDN

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

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

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

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

父定义的附加属性示例

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

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

于 2009-07-23T19:56:17.680 回答
2

简而言之,这就是我的理解方式(如果我错了,请纠正我)。

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

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

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

于 2009-07-23T20:24:03.163 回答