Cómo invalidar los metadatos en una propiedad de dependencia (WPF .NET)

Cuando deriva de una clase que define una propiedad de dependencia, hereda la propiedad de dependencia y sus metadatos. En este artículo se describe cómo puede invalidar los metadatos de una propiedad de dependencia heredada llamando al método OverrideMetadata. La invalidación de los metadatos le permite modificar las características de la propiedad de dependencia heredada para que coincidan con los requisitos específicos de la subclase.

Importante

La documentación de la guía de escritorio para .NET 7 y .NET 6 está en proceso de elaboración.

Información previa

Una clase que define una propiedad de dependencia puede especificar sus características en PropertyMetadata o en uno de sus tipos derivados, como FrameworkPropertyMetadata. Una de esas características es el valor predeterminado de una propiedad de dependencia. Muchas clases que definen propiedades de dependencia especifican los metadatos de la propiedad durante el registro de la propiedad de dependencia. Cuando no se especifican los metadatos durante el registro, el sistema de propiedades de WPF asigna un objeto PropertyMetadata con valores predeterminados. Las clases derivadas que heredan propiedades de dependencia mediante la herencia de clases tienen la opción de invalidar los metadatos originales de cualquier propiedad de dependencia. De esta manera, las clases derivadas pueden modificar selectivamente las características de las propiedades de dependencia para satisfacer los requisitos de la clase. Al llamar a OverrideMetadata(Type, PropertyMetadata), una clase derivada especifica su propio tipo como primer parámetro y una instancia de metadatos como segundo parámetro.

Una clase derivada que invalida los metadatos de una propiedad de dependencia debe hacerlo antes de que el sistema de propiedades ponga la propiedad en uso. Una propiedad de dependencia se pone en uso cuando se crea una instancia de la clase que registra la propiedad. Para ayudar a cumplir este requisito, la clase derivada debe llamar a OverrideMetadata dentro de su constructor estático. Si se invalidan los metadatos de una propiedad de dependencia después de crear una instancia de su tipo de propietario, no se producirán excepciones, pero se producirán comportamientos incoherentes en el sistema de propiedades. Asimismo, un tipo derivado no puede invalidar los metadatos de una propiedad de dependencia más de una vez, y, al intentar hacerlo, se producirá una excepción.

Ejemplo

En el ejemplo siguiente, la clase derivada TropicalAquarium invalida los metadatos de una propiedad de dependencia heredada de la clase base Aquarium. El tipo de metadatos es FrameworkPropertyMetadata, que admite características del marco de WPF relacionadas con la interfaz de usuario como AffectsRender. La clase derivada no invalida la marca AffectsRender heredada, pero actualiza el valor predeterminado de AquariumGraphic en las instancias de la clase derivada.

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

Vea también