如何覆盖依赖属性的元数据 (WPF .NET)

从定义依赖属性的类派生时,就继承了依赖属性及其元数据。 本文介绍如何通过调用 OverrideMetadata 方法来重写继承的依赖属性的元数据。 重写元数据可以修改继承的依赖属性的特征,以匹配特定于子类的要求。

重要

面向 .NET 7 和 .NET 6 的桌面指南文档正在撰写中。

背景

定义依赖属性的类可以在 PropertyMetadata 或其派生类型之一(例如 FrameworkPropertyMetadata)中指定其特征。 其中一个特征是依赖属性的默认值。 许多定义依赖属性的类都在依赖属性注册期间指定属性元数据。 如果在注册期间未指定元数据,则 WPF 属性系统会分配一个具有默认值的 PropertyMetadata 对象。 通过类继承继承依赖属性的派生类可以选择重写任何依赖属性的原始元数据。 通过这种方式,派生类可以选择性地修改依赖属性特性以满足类的要求。 调用 OverrideMetadata(Type, PropertyMetadata) 时,派生类将其自己的类型指定为第一个参数,并将元数据实例指定为第二个参数。

重写依赖属性上的元数据的派生类必须在属性系统使用该属性之前执行此操作。 当注册属性的类的任何实例被实例化时,就会使用依赖属性。 为帮助满足此要求,派生类应在其静态构造函数中调用 OverrideMetadata。 在实例化其所有者类型后重写依赖属性的元数据不会引发异常,但会导致属性系统中的行为不一致。 此外,派生类型不能多次重写依赖属性的元数据,并且尝试这样做将引发异常。

示例

在以下示例中,派生类 TropicalAquarium 重写从基类 Aquarium 继承的依赖属性的元数据。 元数据类型为 FrameworkPropertyMetadata,支持与 UI 相关的 WPF 框架特征,例如 AffectsRender。 派生类不会重写继承的 AffectsRender 标志,但会更新派生类实例上 AquariumGraphic 的默认值。

public class Aquarium : DependencyObject
{
    // Register a dependency property with the specified property name,
    // property type, owner type, and property metadata.
    public static readonly DependencyProperty AquariumGraphicProperty =
        DependencyProperty.Register(
          name: "AquariumGraphic",
          propertyType: typeof(Uri),
          ownerType: typeof(Aquarium),
          typeMetadata: new FrameworkPropertyMetadata(
              defaultValue: new Uri("http://www.contoso.com/aquarium-graphic.jpg"),
              flags: FrameworkPropertyMetadataOptions.AffectsRender)
        );

    // Declare a read-write CLR wrapper with get/set accessors.
    public Uri AquariumGraphic
    {
        get => (Uri)GetValue(AquariumGraphicProperty);
        set => SetValue(AquariumGraphicProperty, value);
    }
}
Public Class Aquarium
    Inherits DependencyObject

    ' Register a dependency property with the specified property name,
    ' property type, owner type, and property metadata.
    Public Shared ReadOnly AquariumGraphicProperty As DependencyProperty =
        DependencyProperty.Register(
            name:="AquariumGraphic",
            propertyType:=GetType(Uri),
            ownerType:=GetType(Aquarium),
            typeMetadata:=New FrameworkPropertyMetadata(
                defaultValue:=New Uri("http://www.contoso.com/aquarium-graphic.jpg"),
                flags:=FrameworkPropertyMetadataOptions.AffectsRender))

    ' Declare a read-write CLR wrapper with get/set accessors.
    Public Property AquariumGraphic As Uri
        Get
            Return CType(GetValue(AquariumGraphicProperty), Uri)
        End Get
        Set
            SetValue(AquariumGraphicProperty, Value)
        End Set
    End Property

End Class
public class TropicalAquarium : Aquarium
{
    // Static constructor.
    static TropicalAquarium()
    {
        // Create a new metadata instance with a modified default value.
        FrameworkPropertyMetadata newPropertyMetadata = new(
            defaultValue: new Uri("http://www.contoso.com/tropical-aquarium-graphic.jpg"));

        // Call OverrideMetadata on the dependency property identifier.
        // Pass in the type for which the new metadata will be applied
        // and the new metadata instance.
        AquariumGraphicProperty.OverrideMetadata(
            forType: typeof(TropicalAquarium),
            typeMetadata: newPropertyMetadata);
    }
}
Public Class TropicalAquarium
    Inherits Aquarium

    ' Static constructor.
    Shared Sub New()
        ' Create a new metadata instance with a modified default value.
        Dim newPropertyMetadata As New FrameworkPropertyMetadata(
            defaultValue:=New Uri("http://www.contoso.com/tropical-aquarium-graphic.jpg"))

        ' Call OverrideMetadata on the dependency property identifier.
        ' Pass in the type for which the new metadata will be applied
        ' and the new metadata instance.
        AquariumGraphicProperty.OverrideMetadata(
            forType:=GetType(TropicalAquarium),
            typeMetadata:=newPropertyMetadata)
    End Sub

End Class

另请参阅