Herança do valor da propriedade (WPF .NET)

A herança de valor de propriedade é um recurso do sistema de propriedades do Windows Presentation Foundation (WPF) e se aplica a propriedades de dependência. A herança do valor da propriedade permite que os elementos filho em uma árvore de elementos obtenham o valor de uma propriedade específica do elemento pai mais próximo. Como um elemento pai também pode ter obtido seu valor de propriedade por meio da herança do valor da propriedade, o sistema potencialmente recorre à raiz da página.

O sistema de propriedades WPF não habilita a herança de valor de propriedade por padrão, e a herança de valor fica inativa, a menos que especificamente habilitada em metadados de propriedade de dependência. Mesmo com a herança de valor de propriedade habilitada, um elemento filho só herdará um valor de propriedade na ausência de um valor de precedência mais alto.

Importante

A documentação do Guia da Área de Trabalho para .NET 7 e .NET 6 está em construção.

Pré-requisitos

O artigo pressupõe um conhecimento básico das propriedades de dependência e que você leu Visão geral das propriedades de dependência. Para seguir os exemplos neste artigo, é útil se você estiver familiarizado com XAML (Extensible Application Markup Language) e souber como escrever aplicativos WPF.

Herança por meio de uma árvore de elementos

A herança de valor de propriedade não é o mesmo conceito que a herança de classe na programação orientada a objeto, onde classes derivadas herdam membros de classe base. Esse tipo de herança também está ativo no WPF, embora em XAML as propriedades de classe base herdadas sejam expostas como atributos de elementos XAML que representam classes derivadas.

A herança do valor da propriedade é o mecanismo pelo qual um valor de propriedade de dependência se propaga de elementos pai para filho dentro de uma árvore de elementos que contêm a propriedade. Na marcação XAML, uma árvore de elementos é visível como elementos aninhados.

O exemplo a seguir mostra elementos aninhados em XAML. O WPF registra a propriedade de dependência na UIElement classe com metadados de propriedade que habilitam a AllowDrop herança do valor da propriedade e define o valor padrão como false. A AllowDrop propriedade de dependência existe em Canvas, e Label elementos, StackPaneluma vez que todos eles derivam de UIElement. Como a AllowDrop propriedade dependency on canvas1 é definida como , o descendente stackPanel1 e label1 os elementos herdam true como trueseu AllowDrop valor.

<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>

Você também pode criar uma árvore de elementos programaticamente adicionando objetos de elemento à coleção de elementos filho de outro objeto de elemento. Em tempo de execução, a herança do valor da propriedade opera na árvore de objetos resultante. No exemplo a seguir, stackPanel2 é adicionado à coleção filho de canvas2. Da mesma forma, label2 é adicionado à coleção filho de stackPanel2. Como a AllowDrop propriedade dependency on canvas2 é definida como , o descendente stackPanel2 e label2 os elementos herdam true como trueseu AllowDrop valor.

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)

Aplicações práticas da herança de valor patrimonial

Propriedades de dependência específicas do WPF têm herança de valor habilitada por padrão, como AllowDrop e FlowDirection. Normalmente, as propriedades com herança de valor habilitada por padrão são implementadas em classes de elemento de interface do usuário base, portanto, elas existem em classes derivadas. Por exemplo, como AllowDrop é implementada UIElement na classe base, essa propriedade de dependência também existe em cada controle derivado de UIElement. O WPF permite a herança de valor em propriedades de dependência para as quais é conveniente para um usuário definir o valor da propriedade uma vez em um elemento pai e fazer com que esse valor de propriedade se propague para elementos descendentes na árvore de elementos.

O modelo de herança de valor de propriedade atribui valores de propriedade, herdados e não herdados, de acordo com a precedência do valor da propriedade de dependência. Portanto, um valor de propriedade de elemento pai só será aplicado a um elemento filho se a propriedade de elemento filho não tiver um valor de precedência mais alto, como um valor definido localmente ou um valor obtido por meio de estilos, modelos ou associação de dados.

A FlowDirection propriedade dependency define a direção do layout do texto e dos elementos filho da interface do usuário em um elemento pai. Normalmente, você esperaria que a direção do fluxo de texto e elementos da interface do usuário dentro de uma página fosse consistente. Como a herança de valor está habilitada nos metadados de propriedade do , um valor só precisa ser definido uma vez na parte superior da árvore de elementos de FlowDirectionuma página. No caso raro em que uma mistura de direções de fluxo é destinada a uma página, uma direção de fluxo diferente pode ser definida em um elemento na árvore atribuindo um valor definido localmente. A nova direção do fluxo se propagará para elementos descendentes abaixo desse nível.

Tornando uma propriedade personalizada hereditária

Você pode tornar uma propriedade de dependência personalizada hereditária habilitando a Inherits propriedade em uma instância de , e registrando sua propriedade de dependência personalizada com essa instância de FrameworkPropertyMetadatametadados. Por padrão, Inherits é definido como false em FrameworkPropertyMetadata. Tornar um valor de propriedade herdado afeta o desempenho, portanto, defina Inherits apenas como true se esse recurso for necessário.

Ao registrar uma propriedade de dependência com Inherits habilitada nos metadados, use o RegisterAttached método conforme descrito em Registrar uma propriedade anexada. Além disso, atribua um valor padrão à propriedade para que exista um valor herdável. Você também pode criar um wrapper de propriedade com get e set acessadores no tipo de proprietário, assim como faria para uma propriedade de dependência não anexada. Dessa forma, você pode definir o valor da propriedade usando o wrapper de propriedade em um proprietário ou tipo derivado. O exemplo a seguir cria uma propriedade de dependência chamada IsTransparent, com Inherits habilitado e um valor padrão de false. O exemplo também inclui um wrapper de propriedade com get e set acessadores.

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

As propriedades anexadas são conceitualmente semelhantes às propriedades globais. Você pode verificar seu valor em qualquer um DependencyObject e obter um resultado válido. O cenário típico para propriedades anexadas é definir valores de propriedade em elementos filho, e esse cenário será mais eficaz se a propriedade em questão estiver implicitamente presente como uma propriedade anexada em cada DependencyObject elemento na árvore.

Herdando valores de propriedade através de limites de árvore

A herança de propriedade funciona percorrendo uma árvore de elementos. Esta árvore geralmente é paralela à árvore lógica. No entanto, sempre que você incluir um objeto de nível de núcleo do WPF, como um Brush, na marcação que define uma árvore de elementos, você criou uma árvore lógica descontínua. Uma árvore lógica verdadeira não se estende conceitualmente pelo Brush, porque a árvore lógica é um conceito de nível de estrutura WPF. Você pode usar os métodos auxiliares de para analisar e exibir a extensão de LogicalTreeHelper uma árvore lógica. A herança de valor de propriedade é capaz de passar valores herdados por meio de uma árvore lógica descontínua, mas somente se a propriedade hereditária foi registrada como uma propriedade anexada e não houver um limite deliberado de bloqueio de herança, como um Frame.

Observação

Embora a herança de valor de propriedade pareça funcionar para propriedades de dependência não anexadas, o comportamento de herança para uma propriedade não anexada por meio de alguns limites de elemento na árvore de tempo de execução é indefinido. Sempre que você especificar Inherits em metadados de propriedade, registre suas propriedades usando RegisterAttached.

Confira também