如何重写依赖属性的元数据

从定义依赖属性的类派生时,将继承依赖属性及其元数据。 本文介绍如何通过调用 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

另请参阅