Compartir a través de


Herencia de valores de propiedad

La herencia de valores de propiedad es una característica del sistema de propiedades de Windows Presentation Foundation (WPF) y se aplica a las propiedades de dependencia. La herencia de valores de propiedad permite que los elementos secundarios de un árbol de elementos obtengan el valor de una propiedad determinada del elemento primario más cercano. Dado que un elemento padre también podría haber obtenido su valor de propiedad a través de la herencia de valores de propiedad, el sistema podría repetirse hasta la raíz de la página.

El sistema de propiedades de WPF no habilita la herencia de valores de propiedad de forma predeterminada y la herencia de valores está inactiva a menos que se habilite específicamente en los metadatos de la propiedad de dependencia. Incluso con la herencia de valores de propiedad habilitada, un elemento secundario solo heredará un valor de propiedad en ausencia de un valor de prioridad mayor.

Prerrequisitos

El artículo asume que tiene un conocimiento básico de las propiedades de dependencia y que ha leído Descripción general de las propiedades de dependencia. Para seguir los ejemplos de este artículo, le ayuda si está familiarizado con el lenguaje de marcado extensible de aplicaciones (XAML) y sabe cómo escribir aplicaciones WPF.

Herencia a través de un árbol de elementos

La herencia de valores de propiedad no es el mismo concepto que la herencia de clases en la programación orientada a objetos, donde las clases derivadas heredan miembros de clase base. Ese tipo de herencia también está activo en WPF, aunque en XAML las propiedades de clase base heredadas se exponen como atributos de elementos XAML que representan clases derivadas.

La herencia de valores de propiedad es el mecanismo por el cual un valor de propiedad dependiente se propaga desde elementos progenitores hacia elementos descendientes dentro de un árbol de elementos que contienen la propiedad. En el marcado XAML, un árbol de elementos es visible como elementos anidados.

En el ejemplo siguiente se muestran los elementos anidados en XAML. WPF registra la propiedad de dependencia AllowDrop en la clase UIElement con metadatos de propiedad que habilitan la herencia de valores de propiedad y establece el valor predeterminado en false. La propiedad de dependencia existe en los elementos AllowDrop, Canvas y StackPanel, ya que todos derivan de Label. Dado que la propiedad de dependencia AllowDrop está establecida en canvas1, los elementos descendientes true y stackPanel1 heredan label1 como su valor true.

<Canvas x:Name="canvas1" Grid.Column="0" Margin="20" Background="Orange" AllowDrop="True">
    <StackPanel Name="stackPanel1" Margin="20" Background="Green">
        <Label Name="label1" Margin="20" Height="40" Width="40" Background="Blue"/>
    </StackPanel>
</Canvas>

También puede crear un árbol de elementos mediante programación agregando objetos de elemento a la colección de elementos secundarios de otro objeto de elemento. En tiempo de ejecución, la herencia de valores de propiedad actúa sobre el árbol de objetos resultante. En el ejemplo siguiente, stackPanel2 se agrega a la colección secundaria de canvas2. Del mismo modo, label2 se agrega a la colección secundaria de stackPanel2. Dado que la propiedad de dependencia AllowDrop está establecida en canvas2, los elementos descendientes true y stackPanel2 heredan label2 como su valor true.

Canvas canvas2 = new()
{
    AllowDrop = true
};
StackPanel stackPanel2 = new();
Label label2 = new();
canvas2.Children.Add(stackPanel2);
stackPanel2.Children.Add(label2);
Dim canvas2 As New Canvas With {
    .AllowDrop = True
}
Dim stackPanel2 As New StackPanel()
Dim label2 As New Label()
canvas2.Children.Add(stackPanel2)
stackPanel2.Children.Add(label2)

Aplicaciones prácticas de herencia de valores de propiedad

Las propiedades de dependencia específicas de WPF tienen habilitada la herencia de valores de forma predeterminada, como AllowDrop y FlowDirection. Normalmente, las propiedades con herencia de valores habilitadas de forma predeterminada se implementan en las clases de elementos base de la interfaz de usuario, por lo que existen en las clases derivadas. Por ejemplo, como AllowDrop se implementa en la UIElement clase base, esa propiedad de dependencia también existe en cada control derivado de UIElement. WPF permite la herencia de valores en las propiedades de dependencia para las que es conveniente que un usuario establezca el valor de propiedad una vez en un elemento primario y que ese valor de propiedad se propague a los elementos descendientes del árbol de elementos.

El modelo de herencia de valores de propiedad asigna valores de propiedad, tanto heredados como no heredados, según la precedencia del valor de propiedad de dependencia. Por lo tanto, un valor de propiedad de elemento primario solo se aplicará a un elemento secundario, si la propiedad del elemento secundario no tiene un valor de precedencia más alto, como un valor establecido localmente o un valor obtenido a través de estilos, plantillas o enlace de datos.

La propiedad de dependencia FlowDirection establece la dirección de diseño del texto y de los elementos de la interfaz de usuario secundarios dentro de un elemento principal. Normalmente, se espera que la dirección de flujo de los elementos de texto y de interfaz de usuario de una página sea coherente. Dado que la herencia de valores está habilitada en los metadatos de propiedad de FlowDirection, un valor solo se debe establecer una vez en la parte superior del árbol de elementos de una página. En el caso poco frecuente en el que una combinación de direcciones de flujo está pensada para una página, se puede establecer una dirección de flujo diferente en un elemento del árbol asignando un valor establecido localmente. A continuación, la nueva dirección del flujo se propagará a los elementos descendientes por debajo de ese nivel.

Hacer que una propiedad personalizada se pueda heredar

Puede hacer que una propiedad de dependencia personalizada se pueda heredar si habilita la propiedad Inherits en una instancia de FrameworkPropertyMetadata, y a continuación, registra la propiedad de dependencia personalizada con esa instancia de metadatos. De forma predeterminada, Inherits se establece en false en FrameworkPropertyMetadata. Hacer que un valor de propiedad se pueda heredar afecta al rendimiento, por lo que solo se establece Inheritstrue en si se necesita esa característica.

Cuando registre una propiedad de dependencia con Inherits habilitada en los metadatos, use el RegisterAttached método tal y como se describe en Registro de una propiedad adjunta. Además, asigne un valor predeterminado a la propiedad para que exista un valor heredable. También puede crear un contenedor de propiedades con get descriptores de acceso y set en el tipo de propietario, igual que lo haría para una propiedad de dependencia no asociada. De este modo, puede establecer el valor de propiedad mediante el contenedor de propiedades en un propietario o un tipo derivado. En el ejemplo siguiente se crea una propiedad de dependencia denominada IsTransparent, con Inherits habilitado y un valor predeterminado de false. En el ejemplo también se incluye un envoltorio de propiedades con get y set accesores.

public class Canvas_IsTransparentInheritEnabled : Canvas
{
    // Register an attached dependency property with the specified
    // property name, property type, owner type, and property metadata
    // (default value is 'false' and property value inheritance is enabled).
    public static readonly DependencyProperty IsTransparentProperty =
        DependencyProperty.RegisterAttached(
            name: "IsTransparent",
            propertyType: typeof(bool),
            ownerType: typeof(Canvas_IsTransparentInheritEnabled),
            defaultMetadata: new FrameworkPropertyMetadata(
                defaultValue: false,
                flags: FrameworkPropertyMetadataOptions.Inherits));

    // Declare a get accessor method.
    public static bool GetIsTransparent(Canvas element)
    {
        return (bool)element.GetValue(IsTransparentProperty);
    }

    // Declare a set accessor method.
    public static void SetIsTransparent(Canvas element, bool value)
    {
        element.SetValue(IsTransparentProperty, value);
    }

    // For convenience, declare a property wrapper with get/set accessors.
    public bool IsTransparent
    {
        get => (bool)GetValue(IsTransparentProperty);
        set => SetValue(IsTransparentProperty, value);
    }
}
Public Class Canvas_IsTransparentInheritEnabled
    Inherits Canvas

    ' Register an attached dependency property with the specified
    ' property name, property type, owner type, and property metadata
    ' (default value is 'false' and property value inheritance is enabled).
    Public Shared ReadOnly IsTransparentProperty As DependencyProperty =
        DependencyProperty.RegisterAttached(
            name:="IsTransparent",
            propertyType:=GetType(Boolean),
            ownerType:=GetType(Canvas_IsTransparentInheritEnabled),
            defaultMetadata:=New FrameworkPropertyMetadata(
                defaultValue:=False,
                flags:=FrameworkPropertyMetadataOptions.[Inherits]))

    ' Declare a get accessor method.
    Public Shared Function GetIsTransparent(element As Canvas) As Boolean
        Return element.GetValue(IsTransparentProperty)
    End Function

    ' Declare a set accessor method.
    Public Shared Sub SetIsTransparent(element As Canvas, value As Boolean)
        element.SetValue(IsTransparentProperty, value)
    End Sub

    ' For convenience, declare a property wrapper with get/set accessors.
    Public Property IsTransparent As Boolean
        Get
            Return GetValue(IsTransparentProperty)
        End Get
        Set(value As Boolean)
            SetValue(IsTransparentProperty, value)
        End Set
    End Property
End Class

Las propiedades adjuntas son conceptualmente similares a las propiedades globales. Puede comprobar su valor en cualquier DependencyObject y obtener un resultado válido. El escenario típico para las propiedades adjuntas es establecer valores de propiedad en elementos secundarios y ese escenario es más eficaz si la propiedad en cuestión está presente implícitamente como una propiedad adjunta en cada DependencyObject elemento del árbol.

Heredar valores de propiedad entre fronteras de árboles

La herencia de propiedades funciona mediante el recorrido de un árbol de elementos. Este árbol suele ser paralelo al árbol lógico. Sin embargo, cada vez que incluya un objeto de nivel central de WPF, como Brush, en el marcado que define un árbol de elementos, habrá creado un árbol lógico discontinuo. Un árbol lógico verdadero no se extiende conceptualmente a través de Brush, porque el árbol lógico es un concepto de nivel de marco de WPF. Puede usar los métodos auxiliares de LogicalTreeHelper para analizar y ver la extensión de un árbol lógico. La herencia de valores de propiedad puede pasar valores heredados a través de un árbol lógico discontinuo, pero solo si la propiedad heredable se registró como una propiedad adjunta y no hay un límite deliberado de bloqueo de herencia, como Frame.

Nota:

Aunque la herencia de valores de propiedad puede parecer funcionar para propiedades de dependencia no adjuntas, el comportamiento de herencia de una propiedad no adjunta a través de algunos límites de elemento en el árbol en tiempo de ejecución no está definido. Siempre que especifique Inherits en los metadatos de propiedad, registre las propiedades mediante RegisterAttached.

Consulte también