属性值继承

属性值继承是 Windows Presentation Foundation (WPF) 属性系统的一项功能。 属性值继承使元素树中的子元素可以从父元素获取特定属性的值,并继承该值,就如同它是在最近的父元素中任意位置设置的一样。 父元素可能也已通过属性值继承获得了其值,因此系统有可能一直递归到页面根。 属性值继承不是默认属性系统行为;属性必须用特定的元数据设置来建立,以便使该属性对子元素启动属性值继承。

属性值继承是内含继承

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

属性值继承的实际应用

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

使自定义属性可继承

通过更改自定义属性的元数据,还可以使自己的自定义属性可继承。 但是,请注意,将属性指定为可继承需要考虑到性能问题。 如果该属性没有已建立的本地值或通过样式、模板或数据绑定获取的值,则可继承的属性会将赋予它的属性值提供给逻辑树中的所有子元素。

为了让属性参与值继承,请按照注册附加属性中所述创建自定义附加属性。 向元数据 (FrameworkPropertyMetadata) 注册属性,并在该元数据内的选项设置中指定“Inherits”选项。 同时确保该属性已建立了默认值,因为该值现将继承。 尽管已将该属性注册为附加属性,可能还需像对“非附加”依赖项属性一样,为所有者类型上的 get/set 访问创建属性“包装”。 然后,可通过对所有者类型或派生类型使用直接属性包装或通过对任意 DependencyObject 使用附加属性语法,来设置可继承属性。

附加属性在概念上与全局属性类似;可检查任意 DependencyObject 上的值并获取有效的结果。 附加属性的典型方案是针对子元素设置属性值,如果所涉及的属性是一个在树中的每个元素 (DependencyObject) 上都始终作为附加属性存在的附加属性,则该方案会更为有效。

注意

尽管属性值继承看起来对非附加依赖项属性有效,但通过运行时树中特定元素边界的非附加属性的继承行为并未定义。 始终使用 RegisterAttached 来注册在元数据中指定 Inherits 的属性。

跨树边界继承属性值

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

另请参阅