属性值继承

属性值继承是 Windows Presentation Foundation (WPF) 属性系统的一项功能。 属性值继承使元素树中的子元素能够从父元素中获取特定属性的值,并在最接近的父元素中的任意位置设置该值时继承该值。 父元素也可能通过属性值继承获取其值,因此系统可能会一路递归到页面根目录。 属性值继承不是默认属性系统行为;必须使用特定的元数据设置建立属性,以便使该属性在子元素上启动属性值继承。

属性值继承是内含继承

此处的术语“继承”与类型上下文和常规面向对象的编程中的继承概念并不完全相同,即派生类从其基类继承成员定义。 继承的含义在 WPF 中也处于活动状态:在各种基类中定义的属性在用作元素时作为派生 XAML 类的属性公开,并作为代码的成员公开。 属性值继承则是关于属性值如何基于元素树中的父子关系从一个元素继承到另一个元素。 在 XAML 标记中定义应用程序时,当将元素嵌套在其他元素内时,该元素树最直接可见。 对象树也可以通过编程方式,通过在其他对象的指定集合中添加对象来创建。在运行时,属性值的继承在完成的树中以相同的方式工作。

属性值继承的实际应用

WPF API 包括几个启用了属性继承的属性。 通常,这类情况涉及一个属性,该属性适合在每个页面中只设置一次,但它也是某个基元素类的成员,因此也会出现在大多数子元素上。 例如,FlowDirection 属性用于控制页面上流式内容的呈现和排列方向。 通常做法是在所有子元素中以一致的方式处理文本流概念。 如果用户或环境操作因某种原因在元素树的某一层重置了流方向,则流方向通常会在整个树中重置。 当 FlowDirection 属性进行继承时,只需在包含应用程序中每个页面的呈现需求的元素树级别设置或重置一次值。 即使是初始默认值也会以这种方式继承。 在需有意混用流方向的极罕见情况下,属性值继承模型也仍允许个别元素重置该值。

使自定义属性可继承

通过更改自定义属性的元数据,还可以使自己的自定义属性可继承。 但是,请注意,将属性指定为可继承属性确实具有一些性能注意事项。 如果该属性没有已建立的本地值,或者通过样式、模板或数据绑定获取的值,则可继承属性会将其分配的属性值提供给逻辑树中的所有子元素。

若要使属性参与值继承,请创建自定义附加属性,如 注册附加属性中所述。 将属性注册到元数据(FrameworkPropertyMetadata),并在该元数据中的选项设置中指定“继承”选项。 此外,请确保该属性具有已建立的默认值,因为该值现在将继承。 尽管已将属性注册为附加属性,但你可能还需要创建属性“包装器”,以便在所有者类型上获取/设置访问权限,就像对“非附加”依赖属性一样。 执行此操作后,可以通过对所有者类型或派生类型使用直接属性包装来设置可继承属性,也可以通过使用任何 DependencyObject的附加属性语法进行设置。

附加属性在概念上类似于全局属性;可以检查任何 DependencyObject 的值并获取有效的结果。 附加属性的典型方案是在子元素上设置属性值,如果相关属性是始终作为树中每个元素(DependencyObject)上的附加属性隐式存在的附加属性,则该方案更有效。

说明

尽管属性值继承可能适用于非附加依赖属性,但未定义通过运行时树中的某些元素边界的非附加属性的继承行为。 始终使用 RegisterAttached 来注册在元数据中指定 Inherits 的属性。

跨树边界继承属性值

属性继承的工作原理是遍历元素树。 此树通常与逻辑树并行。 但是,只要在标记中包含 WPF 核心级对象来定义元素树(如 Brush),就创建了一个不连续的逻辑树。 真正的逻辑树在概念上不会通过 Brush进行扩展,因为逻辑树是 WPF 框架级概念。 使用 LogicalTreeHelper的方法时,你可以看到这反映在结果中。 但是,只要可继承的属性注册为附加属性,且没有遇到有意的继承阻止边界(如 Frame),那么属性值继承就可以弥合逻辑树中的这种差异,并且仍可遍历传递所继承的值。

另请参阅