【问题标题】:How exactly do Attached Properties work in WPF?附加属性在 WPF 中究竟是如何工作的?
【发布时间】:2009-07-23 18:06:36
【问题描述】:

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

【问题讨论】:

    标签: wpf xaml attached-properties


    【解决方案1】:

    这里有两个概念:依赖属性附加依赖属性。 “附加属性”是依赖属性,因此支持依赖property value inheritance

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

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

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

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

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

    作为附加说明,继承附加属性的一个很好的例子是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));
    

    【讨论】:

    • 有趣且内容丰富。但是,这种情况如何:一个 2x2 网格 (A) 包含一个 2x2 网格 (B)。网格 B 包含一个按钮。如果网格 B 将其 Grid.Column 附加属性设置为 1(因此它出现在其父网格的第二列,网格 A),不应该该附加属性向下级联到网格 B 的按钮,因此按钮出现在第二个网格 B 的列?
    【解决方案2】:

    来自MSDN

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

    • 定义附加的类型 财产被设计成它可以 成为元素的父元素 这将为附件设置值 财产。然后该类型迭代其 通过内部逻辑的子对象 针对一些对象树结构, 获取值,并作用于那些 以某种方式价值。

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

    • 定义附加的类型 属性代表服务。其他 类型为附件设置值 财产。然后,当元素 设置属性在 服务的上下文,附件 属性值是通过 服务类的内部逻辑。

    父定义的附加属性示例

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

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

    【讨论】:

      【解决方案3】:

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

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

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

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2023-04-01
        • 1970-01-01
        • 2011-06-26
        • 2021-08-15
        • 2012-06-08
        • 2011-10-11
        • 2013-07-05
        相关资源
        最近更新 更多