如何重写依赖属性的元数据(WPF .NET)

从定义依赖属性的类派生时,将继承依赖属性及其元数据。 本文介绍如何通过调用 OverrideMetadata 方法替代继承的依赖属性的元数据。 通过覆盖元数据可以使您能够修改继承的依赖属性的特征,以满足子类特定的要求。

背景

定义依赖属性的类可以在 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

另请参阅