我有一个附加属性,它指定“继承”选项来实现 WPF 属性值继承。我可以看到属性值在可视化树中传播。 然而,对于大型视觉树,这可能会对性能产生相当大的影响。
因此,我希望我的附加属性的附加属性值继承停止在某些边界,更具体地说是特定类的实例。
我读过有关 FrameworkElement.InheritanceBehavior 的内容,控件可以将其设置为 SkipAllNext 之类的内容,这会停止属性值继承(尽管对于所有属性),但也会影响资源查找。对资源查找的影响并不理想。
是否有其他方法可以控制传播,无论是在附加属性中还是在应充当边界的类中?
我想要实现的目标在这里:WPF容器将所有子控件变为只读。具有值继承的解决方案可以根据全局开关将表单中的所有控件变为只读,这非常好。它只是有性能损失,如此处和此处所述。
AddOwner 似乎有效:
class BoundaryElement : FrameworkElement {
public static readonly DependencyProperty CustomProperty =
AttachedProperties.CustomProperty.AddOwner(typeof(BoundaryElement),
new FrameworkPropertyMetadata() {Inherits = false});
}
我尝试通过
Inherits = false
设置 OverrideMetadata
,但这只会影响 BoundaryElement
本身,并且附加的属性值会继续传播到其子级。 AddOwner
有效地替换了 BoundaryElement
处的属性,因此原始属性不存在可继承。
我知道有一种可能性。这并不是您真正想要的,但您可以使用
DependencyProperty.OverrideMetadata
方法来覆盖扩展控件中 PropertyMetadata
的 DependencyProperty
:
public class SomeControl : OriginalControl
{
static SomeControl()
{
OriginalControl.SomeProperty.OverrideMetadata(typeof(SomeControl),
new FrameworkPropertyMetadata(defaultValue,
FrameworkPropertyMetadataOptions.OverridesInheritanceBehavior));
}
}
除此之外,(我可能是错的,但是)我认为您无法实现您的目标...WPF 并不是这样设计的。
对此的解释有点悲伤和复杂,但幸运的是解决方案非常简单。您不需要使用
AddOwner(...)
。
要在使用
DependencyProperty.OverrideMetadata(...)
时阻止继承,不能使用 FrameworkPropertyMetadata
构造函数 来指定 FrameworkPropertyMetadataOptions
标志“OverridesInheritanceBehavior
”。原因是,对于某些 FPMO 标志,默认 FrameworkPropertyMetadata.Merge(...)
函数仅处理已通过 FPM 属性设置器显式修改的标志。
Inherits
标志/属性是另一个也具有此行为的标志/属性,并且您还需要从任何基础元数据中清除它。因此,获得 Merge(...)
clear 结果值(与基本属性元数据合并后)的唯一方法是再次通过其 FPM setter 显式设置它。
这很令人困惑,不幸的是,这是一个非常不自然/意外/不明显的设计,所以这里有一个例子。假设
SomeDependencyProperty
是 bool
属性,并且基础元数据指定 DefaultValue
的 false
,并且启用了 DP 继承。您想要在派生类 true
上将默认值覆盖为 MyType
。
因此,此页面/问题讨论的整个问题是以下内容不起作用:
SomeDependencyProperty.OverrideMetadata(typeof(MyType),
new FrameworkPropertyMetadata(true, FrameworkPropertyMetadataOptions.OverridesInheritanceBehavior));
如上所述,前面有两个问题,但更明显的一个是,即使
FPMO.OverridesInheritanceBehavior
按预期工作,您也没有 un-set FPMO.Inherits
标志本身。显然,无法通过 ORing
和只能断言的位标志来取消设置位标志。因此,本质上,在 Merge
之后,您将覆盖继承行为 - 但继承仍然处于启用状态(由于 Merge
)。最后,在继承最终仍然启用的情况下,您想要的 DefaultValue
基本上不会产生任何效果。
相反,请使用属性设置器,如下所示,它可以阻止继承,从而允许修改的
DefaultValue
生效:
SomeDependencyProperty.OverrideMetadata(typeof(MyType),
new FrameworkPropertyMetadata(true)
{
Inherits = false,
OverridesInheritanceBehavior = true,
});
您还可以通过样式停止值继承,例如:
static BoundaryElement()
{
Style style = new Style(typeof(BoundaryElement));
style.Setters.Add(new Setter(CustomProperty, defaultValue));
style.Seal();
StyleProperty.OverrideMetadata(
typeof(BoundaryElement), new FrameworkPropertyMetadata(style));
}
这就是 Image 元素如何停止继承 FlowDirection 属性的方式(尽管它没有子元素)。