Ereditarietà del valore della proprietà (WPF .NET)

L'ereditarietà del valore della proprietà è una funzionalità del sistema di proprietà Windows Presentation Foundation (WPF) e si applica alle proprietà di dipendenza. L'ereditarietà del valore della proprietà consente agli elementi figlio in un albero di elementi di ottenere il valore di una determinata proprietà dall'elemento padre più vicino. Poiché un elemento padre potrebbe anche aver ottenuto il valore della proprietà tramite l'ereditarietà del valore della proprietà, il sistema potenzialmente torna alla radice della pagina.

Il sistema di proprietà WPF non abilita l'ereditarietà del valore della proprietà per impostazione predefinita e l'ereditarietà dei valori è inattiva, a meno che non sia specificatamente abilitata nei metadati della proprietà di dipendenza. Anche se l'ereditarietà del valore della proprietà è abilitata, un elemento figlio erediterà solo un valore della proprietà in assenza di un valore di precedenza superiore.

Prerequisiti

L'articolo presuppone una conoscenza di base delle proprietà di dipendenza e che si abbia letto Panoramica delle proprietà di dipendenza. Per seguire gli esempi in questo articolo, è utile se si ha familiarità con Extensible Application Markup Language (XAML) e si sa come scrivere applicazioni WPF.

Ereditarietà tramite un albero di elementi

L'ereditarietà del valore della proprietà non è lo stesso concetto dell'ereditarietà della classe nella programmazione orientata agli oggetti, in cui le classi derivate ereditano membri della classe base. Questo tipo di ereditarietà è attivo anche in WPF, anche se in XAML le proprietà della classe di base ereditate vengono esposte come attributi di elementi XAML che rappresentano classi derivate.

L'ereditarietà del valore della proprietà è il meccanismo in base al quale un valore della proprietà di dipendenza viene propagato da elementi padre a figlio all'interno di un albero di elementi che contengono la proprietà . Nel markup XAML un albero di elementi è visibile come elementi annidati.

L'esempio seguente mostra gli elementi annidati in XAML. WPF registra la AllowDrop proprietà di dipendenza nella classe con i metadati della UIElement proprietà che abilita l'ereditarietà del valore della proprietà e imposta il valore predefinito su false. La AllowDrop proprietà di dipendenza esiste negli Canvaselementi , StackPanele Label poiché derivano tutti da UIElement. Poiché la AllowDrop proprietà di dipendenza su canvas1 è impostata su true, i discendenti stackPanel1 e label1 gli elementi ereditano true come valore AllowDrop .

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

È anche possibile creare un albero di elementi a livello di codice aggiungendo oggetti elemento alla raccolta di elementi figlio di un altro oggetto elemento. In fase di esecuzione, l'ereditarietà del valore della proprietà opera sull'albero degli oggetti risultante. Nell'esempio seguente viene stackPanel2 aggiunto alla raccolta figlio di canvas2. Analogamente, label2 viene aggiunto alla raccolta figlio di stackPanel2. Poiché la AllowDrop proprietà di dipendenza su canvas2 è impostata su true, i discendenti stackPanel2 e label2 gli elementi ereditano true come valore AllowDrop .

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)

Applicazioni pratiche di ereditarietà dei valori di proprietà

Le proprietà di dipendenza WPF specifiche hanno l'ereditarietà dei valori abilitata per impostazione predefinita, ad esempio AllowDrop e FlowDirection. In genere, le proprietà con ereditarietà dei valori abilitate per impostazione predefinita vengono implementate nelle classi degli elementi dell'interfaccia utente di base, in modo che esistano nelle classi derivate. Ad esempio, poiché AllowDrop viene implementato nella UIElement classe base, tale proprietà di dipendenza esiste anche in ogni controllo derivato da UIElement. WPF abilita l'ereditarietà dei valori nelle proprietà di dipendenza per le quali un utente può impostare il valore della proprietà una sola volta su un elemento padre e propagare tale valore di proprietà agli elementi discendenti nell'albero degli elementi.

Il modello di ereditarietà del valore della proprietà assegna valori di proprietà, ereditati e non inriti, in base alla precedenza del valore della proprietà di dipendenza. Pertanto, un valore della proprietà dell'elemento padre verrà applicato solo a un elemento figlio, se la proprietà dell'elemento figlio non ha un valore di precedenza superiore, ad esempio un valore impostato localmente o un valore ottenuto tramite stili, modelli o data binding.

La FlowDirection proprietà di dipendenza imposta la direzione del layout degli elementi di testo e dell'interfaccia utente figlio all'interno di un elemento padre. In genere, si prevede che la direzione del flusso degli elementi di testo e interfaccia utente all'interno di una pagina sia coerente. Poiché l'ereditarietà dei valori è abilitata nei metadati della proprietà di FlowDirection, è necessario impostare un valore una sola volta nella parte superiore dell'albero degli elementi per una pagina. Nel raro caso in cui una combinazione di direzioni di flusso sia destinata a una pagina, è possibile impostare una direzione di flusso diversa su un elemento dell'albero assegnando un valore impostato localmente. La nuova direzione del flusso verrà quindi propagata agli elementi discendenti al di sotto di tale livello.

Rendere ereditabile una proprietà personalizzata

È possibile rendere ereditabile una proprietà di dipendenza personalizzata abilitando la Inherits proprietà in un'istanza di FrameworkPropertyMetadatae quindi registrando la proprietà di dipendenza personalizzata con tale istanza di metadati. Per impostazione predefinita, Inherits è impostato su false in FrameworkPropertyMetadata. La creazione di un valore di proprietà ereditabile influisce sulle prestazioni, quindi è impostata Inherits true su solo se tale funzionalità è necessaria.

Quando si registra una proprietà di dipendenza con Inherits abilitata nei metadati, usare il RegisterAttached metodo come descritto in Registrare una proprietà associata. Assegnare inoltre un valore predefinito alla proprietà in modo che esista un valore ereditabile. È anche possibile creare un wrapper di proprietà con get e set funzioni di accesso nel tipo di proprietario, proprio come per una proprietà di dipendenza non associata. In questo modo è possibile impostare il valore della proprietà usando il wrapper della proprietà in un tipo proprietario o derivato. Nell'esempio seguente viene creata una proprietà di dipendenza denominata IsTransparent, con Inherits abilitato e un valore predefinito .false L'esempio include anche un wrapper di proprietà con get le funzioni di accesso e set .

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

Le proprietà associate sono concettualmente simili alle proprietà globali. È possibile controllare il relativo valore su qualsiasi DependencyObject e ottenere un risultato valido. Lo scenario tipico per le proprietà associate consiste nell'impostare i valori delle proprietà sugli elementi figlio e tale scenario è più efficace se la proprietà in questione è implicitamente presente come proprietà associata per ogni DependencyObject elemento dell'albero.

Ereditarietà dei valori delle proprietà tra i limiti dell'albero

L'ereditarietà delle proprietà funziona mediante il passaggio attraverso un albero di elementi. Quest'albero spesso è parallelo all'albero logico. Tuttavia, ogni volta che si include un oggetto a livello di core WPF, ad esempio , Brushnel markup che definisce un albero degli elementi, è stato creato un albero logico discontinuo. Un vero albero logico non si estende concettualmente attraverso , Brushperché l'albero logico è un concetto a livello di framework WPF. È possibile usare i metodi helper di LogicalTreeHelper per analizzare e visualizzare l'estensione di un albero logico. L'ereditarietà del valore della proprietà è in grado di passare valori ereditati tramite un albero logico discontinuo, ma solo se la proprietà ereditabile è stata registrata come proprietà associata e non esiste un limite intenzionale di blocco dell'ereditarietà, ad esempio .Frame

Nota

Anche se l'ereditarietà dei valori di proprietà potrebbe funzionare per le proprietà di dipendenza non associate, il comportamento di ereditarietà per una proprietà non associata attraverso alcuni limiti di elemento nell'albero di runtime non è definito. Ogni volta che si specifica Inherits nei metadati delle proprietà, registrare le proprietà usando RegisterAttached.

Vedi anche