Precedenza del valore della proprietà di dipendenza (WPF .NET)

Le operazioni del sistema di proprietà Windows Presentation Foundation (WPF) influiscono sul valore di una proprietà di dipendenza. Questo articolo illustra in che modo la precedenza di input diversi basati su proprietà all'interno del sistema di proprietà WPF determina il valore effettivo di una proprietà di dipendenza.

Importante

La documentazione di Desktop Guide per .NET 7 e .NET 6 è in fase di costruzione.

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.

Sistema di proprietà WPF

Il sistema di proprietà WPF usa diversi fattori per determinare il valore delle proprietà di dipendenza, ad esempio la convalida delle proprietà in tempo reale, l'associazione tardiva e le notifiche di modifica delle proprietà per le proprietà correlate. Anche se l'ordine e la logica usati per determinare i valori delle proprietà di dipendenza sono complessi, l'apprendimento può aiutare a evitare le impostazioni delle proprietà non necessarie e anche a capire perché un tentativo di impostare una proprietà di dipendenza non ha comportato il valore previsto.

Proprietà di dipendenza impostate in più posizioni

L'esempio XAML seguente mostra come tre diverse operazioni "set" sulla proprietà del Background pulsante possano influenzare il relativo valore.

<StackPanel>
    <StackPanel.Resources>
        <ControlTemplate x:Key="ButtonTemplate" TargetType="{x:Type Button}">
            <Border Background="{TemplateBinding Background}" BorderThickness="{TemplateBinding BorderThickness}" 
                    BorderBrush="{TemplateBinding BorderBrush}">
                <ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center" />
            </Border>
        </ControlTemplate>
    </StackPanel.Resources>

    <Button Template="{StaticResource ButtonTemplate}" Background="Red">
        <Button.Style>
            <Style TargetType="{x:Type Button}">
                <Setter Property="Background" Value="Blue"/>
                <Style.Triggers>
                    <Trigger Property="IsMouseOver" Value="True">
                        <Setter Property="Background" Value="Yellow" />
                    </Trigger>
                </Style.Triggers>
            </Style>
        </Button.Style>
        Which color do you expect?
    </Button>
</StackPanel>

Nell'esempio la Background proprietà è impostata localmente su Red. Tuttavia, lo stile implicito dichiarato nell'ambito del pulsante tenta di impostare la Background proprietà su Blue. Inoltre, quando il mouse si trova sul pulsante, il trigger nello stile implicito tenta di impostare la Background proprietà su Yellow. Ad eccezione della coercizione e dell'animazione, un valore della proprietà impostata localmente ha la precedenza più alta, quindi il pulsante sarà rosso, anche su mouseover. Tuttavia, se si rimuove il valore impostato localmente dal pulsante, il valore Background verrà ottenuto dallo stile. All'interno di uno stile, i trigger hanno la precedenza, quindi il pulsante sarà giallo sul mouse e blu in caso contrario. L'esempio sostituisce l'impostazione predefinita ControlTemplate del pulsante perché il modello predefinito ha un valore di mouseover Background hardcoded.

Elenco di precedenza delle proprietà di dipendenza

L'elenco seguente è l'ordine di precedenza definitivo usato dal sistema di proprietà quando si assegnano valori di runtime alle proprietà di dipendenza. La precedenza più elevata viene elencata per prima.

  1. Coercizione del sistema di proprietà. Per altre informazioni sulla coercizione, vedi Coercizione e animazioni.

  2. Animazioni attive o animazioni con un comportamento di attesa. Per avere un effetto pratico, un valore di animazione deve avere la precedenza sul valore di base (senzanimazione), anche se il valore di base è stato impostato localmente. Per altre informazioni, vedi Coercizione e animazioni.

  3. Valori locali. Puoi impostare un valore locale tramite una proprietà "wrapper", che equivale all'impostazione di un attributo o di un elemento di proprietà in XAML o tramite una chiamata all'API usando una proprietà di un'istanza SetValue specifica. Un valore locale impostato tramite un'associazione o una risorsa avrà la stessa precedenza di un valore impostato direttamente.

  4. Valori delle proprietà del modello TemplatedParent. Un elemento ha un TemplatedParent se è stato creato da un modello (ControlTemplate o DataTemplate). Per altre informazioni, vedere TemplatedParent. All'interno del modello specificato da TemplatedParent, l'ordine di precedenza è:

    1. Triggers (Trigger).

    2. Set di proprietà, in genere tramite attributi XAML.

  5. Stili impliciti. Si applica solo alla proprietà Style. Il Style valore è qualsiasi risorsa di stile con un TargetType valore corrispondente al tipo di elemento. La risorsa di stile deve esistere all'interno della pagina o dell'applicazione. La ricerca di una risorsa di stile implicita non si estende alle risorse degli stili in Temi.

  6. Trigger degli stili. Un trigger di stile è un trigger all'interno di uno stile esplicito o implicito. Lo stile deve esistere all'interno della pagina o dell'applicazione. I trigger negli stili predefiniti hanno una precedenza inferiore.

  7. Trigger dei modelli. Un trigger di modello è un trigger da un modello applicato direttamente o da un modello all'interno di uno stile. Lo stile deve esistere all'interno della pagina o dell'applicazione.

  8. Valori del setter di stile. Un valore setter di stile è un valore applicato da un oggetto all'interno di Setter uno stile. Lo stile deve esistere all'interno della pagina o dell'applicazione.

  9. Stili predefiniti, noti anche come stili del tema. Per altre informazioni, vedere Stili predefiniti (tema). All'interno di uno stile predefinito, l'ordine di precedenza è:

    1. Trigger attivi.

    2. Setter.

  10. Ereditarietà. Alcune proprietà di dipendenza di un elemento figlio ereditano il valore dall'elemento padre. Potrebbe quindi non essere necessario impostare i valori delle proprietà su ogni elemento nell'applicazione. Per altre informazioni, vedere Ereditarietà dei valori delle proprietà.

  11. Valore predefinito dai metadati della proprietà di dipendenza Una proprietà di dipendenza può avere un valore predefinito impostato durante la registrazione del sistema di proprietà di tale proprietà. Le classi derivate che ereditano una proprietà di dipendenza possono eseguire l'override dei metadati delle proprietà di dipendenza (incluso il valore predefinito) in base al tipo. Per altre informazioni, vedere Metadati delle proprietà di dipendenza. Per una proprietà ereditata, il valore predefinito di un elemento padre ha la precedenza sul valore predefinito di un elemento figlio. Pertanto, se non è impostata una proprietà ereditabile, viene usato il valore predefinito della radice o dell'elemento padre anziché il valore predefinito dell'elemento figlio.

TemplatedParent

TemplatedParent la precedenza non si applica alle proprietà degli elementi dichiarati direttamente nel markup dell'applicazione standard. Il TemplatedParent concetto esiste solo per gli elementi figlio all'interno di una struttura ad albero visuale che si presentano tramite l'applicazione di un modello. Quando il sistema di proprietà cerca nel modello specificato da TemplatedParent per i valori delle proprietà di un elemento, esegue una ricerca nel modello che ha creato l'elemento. I valori delle proprietà del TemplatedParent modello fungono in genere come se fossero valori impostati localmente nell'elemento, ma con una precedenza minore rispetto ai valori locali effettivi perché i modelli sono potenzialmente condivisi. Per ulteriori informazioni, vedere TemplatedParent.

Proprietà Style

Lo stesso ordine di precedenza si applica a tutte le proprietà di dipendenza, ad eccezione della Style proprietà . La Style proprietà è univoca in quanto non può essere impostata come stile. Non è consigliabile animare o animare la Style proprietà e animare la Style proprietà richiederebbe una classe di animazione personalizzata. Di conseguenza, non si applicano tutti gli elementi di precedenza. Esistono solo tre modi per impostare la Style proprietà:

  • Stile esplicito. La Style proprietà di un elemento viene impostata direttamente. Il valore della Style proprietà funge da valore locale e ha la stessa precedenza dell'elemento 3 nell'elenco di precedenza. Nella maggior parte degli scenari, gli stili espliciti non sono definiti inline e vengono invece indicati in modo esplicito come risorsa, ad esempio Style="{StaticResource myResourceKey}".

  • Stile implicito. La Style proprietà di un elemento non viene impostata direttamente. Al contrario, uno stile viene applicato quando esiste a un certo livello all'interno della pagina o dell'applicazione e ha una chiave di risorsa che corrisponde al tipo di elemento a cui si applica lo stile, ad esempio <Style TargetType="x:Type Button">. Il tipo deve corrispondere esattamente, ad esempio <Style TargetType="x:Type Button"> non verrà applicato al MyButton tipo anche se MyButton è derivato da Button. Il valore della Style proprietà ha la stessa precedenza dell'elemento 5 nell'elenco di precedenza. È possibile rilevare un valore di stile implicito chiamando il DependencyPropertyHelper.GetValueSource metodo , passando la Style proprietà e controllando ImplicitStyleReference i risultati.

  • Stile predefinito, noto anche come stile del tema. La Style proprietà di un elemento non viene impostata direttamente. Proviene invece dalla valutazione del tema di runtime dal motore di presentazione WPF. Prima del runtime, il valore della Style proprietà è null. Il valore della Style proprietà ha la stessa precedenza dell'elemento 9 nell'elenco di precedenza.

Stili predefiniti (tema)

Ogni controllo fornito con WPF ha uno stile predefinito che può variare in base al tema, motivo per cui lo stile predefinito viene talvolta definito stile del tema.

ControlTemplate è un elemento importante all'interno dello stile predefinito per un controllo . ControlTemplate è un valore setter per la proprietà dello Template stile. Se gli stili predefiniti non contengono un modello, un controllo senza un modello personalizzato come parte di uno stile personalizzato non avrà alcun aspetto visivo. Non solo un modello definisce l'aspetto visivo di un controllo, ma definisce anche le connessioni tra le proprietà nella struttura ad albero visuale del modello e la classe di controllo corrispondente. Ogni controllo espone un set di proprietà che possono influenzare l'aspetto visivo del controllo senza sostituire il modello. Si consideri ad esempio l'aspetto visivo predefinito di un Thumb controllo , che è un ScrollBar componente.

Un Thumb controllo ha alcune proprietà personalizzabili. Il modello predefinito di un Thumb controllo crea una struttura di base o una struttura ad albero visuale, con diversi componenti annidati Border per creare un aspetto a rilievo. All'interno del modello, le proprietà che devono essere personalizzabili dalla Thumb classe vengono esposte tramite TemplateBinding. Il modello predefinito per il Thumb controllo ha varie proprietà del bordo che condividono un'associazione di modelli con proprietà come Background o BorderThickness. Tuttavia, dove i valori per le proprietà o le disposizioni visive sono hardcoded nel modello o sono associati a valori provenienti direttamente dal tema, è possibile modificare tali valori solo sostituendo l'intero modello. In genere, se una proprietà proviene da un elemento padre basato su modelli e non è esposta da un TemplateBindingoggetto , il valore della proprietà non può essere modificato dagli stili perché non esiste un modo pratico per impostarlo come destinazione. Tuttavia, tale proprietà potrebbe comunque essere influenzata dall'ereditarietà del valore della proprietà nel modello applicato o da un valore predefinito.

Gli stili predefiniti specificano un oggetto TargetType nelle relative definizioni. La valutazione del tema di runtime corrisponde a TargetType di uno stile predefinito alla DefaultStyleKey proprietà di un controllo . Al contrario, il comportamento di ricerca per gli stili impliciti usa il tipo effettivo del controllo. Il valore di DefaultStyleKey viene ereditato dalle classi derivate, quindi gli elementi derivati che altrimenti non hanno uno stile associato ottengono un aspetto visivo predefinito. Ad esempio, se si deriva MyButton da Button, MyButton erediterà il modello predefinito di Button. Le classi derivate possono eseguire l'override del valore predefinito di nei metadati delle proprietà di DefaultStyleKey dipendenza. Pertanto, se si vuole una rappresentazione visiva diversa per MyButton, è possibile eseguire l'override dei metadati della proprietà di dipendenza per DefaultStyleKey in MyButtone quindi definire lo stile predefinito pertinente, incluso un modello, che verrà incluso nel pacchetto con il MyButton controllo. Per altre informazioni, vedere Cenni preliminari sulla creazione di controlli.

Risorsa dinamica

I riferimenti alle risorse dinamiche e le operazioni di associazione hanno la precedenza della posizione in cui sono impostati. Ad esempio, una risorsa dinamica applicata a un valore locale ha la stessa precedenza dell'elemento 3 nell'elenco di precedenza. Come altro esempio, un'associazione di risorse dinamica applicata a un setter di proprietà all'interno di uno stile predefinito ha la stessa precedenza dell'elemento 9 nell'elenco di precedenza. Poiché i riferimenti alle risorse dinamiche e l'associazione devono ottenere valori dallo stato di runtime dell'applicazione, il processo per determinare la precedenza del valore della proprietà per una determinata proprietà si estende in runtime.

I riferimenti alle risorse dinamiche non fanno tecnicamente parte del sistema di proprietà e hanno un proprio ordine di ricerca che interagisce con l'elenco di precedenza. Essenzialmente, la precedenza dei riferimenti alle risorse dinamiche è: elemento per la radice della pagina, l'applicazione, il tema e quindi il sistema. Per altre informazioni, vedere Risorse XAML.

Anche se i riferimenti alle risorse dinamiche e le associazioni hanno la precedenza della posizione in cui vengono impostati, il valore viene posticipato. Una conseguenza di questo è che se si imposta una risorsa dinamica o un'associazione a un valore locale, qualsiasi modifica al valore locale sostituisce interamente la risorsa o l'associazione dinamica. Anche se si chiama il ClearValue metodo per cancellare il valore impostato in locale, la risorsa dinamica o l'associazione non verranno ripristinate. Infatti, se si chiama ClearValue su una proprietà con una risorsa dinamica o un'associazione (senza valore locale letterale), la risorsa dinamica o l'associazione verranno cancellate.

SetCurrentValue

Il SetCurrentValue metodo è un altro modo per impostare una proprietà, ma non nell'elenco di precedenza. SetCurrentValue consente di modificare il valore di una proprietà senza sovrascrivere l'origine di un valore precedente. Ad esempio, se una proprietà viene impostata da un trigger e quindi si assegna un altro valore usando SetCurrentValue, l'azione trigger successiva imposta nuovamente la proprietà sul valore del trigger. È possibile usare SetCurrentValue ogni volta che si desidera impostare un valore della proprietà senza assegnare tale valore al livello di precedenza di un valore locale. Analogamente, è possibile usare SetCurrentValue per modificare il valore di una proprietà senza sovrascrivere un'associazione.

Coercizione e animazione

La coercizione e l'animazione agiscono entrambi su un valore di base. Il valore di base è il valore della proprietà di dipendenza con la precedenza più alta, determinata dalla valutazione verso l'alto tramite l'elenco di precedenza fino al raggiungimento dell'elemento 2.

Se un'animazione non specifica valori di proprietà e FromTo per determinati comportamenti o se l'animazione torna deliberatamente al valore di base al termine, il valore di base può influire sul valore animato. Per verificarlo in pratica, eseguire l'applicazione di esempio Valori di destinazione. Nell'esempio, per l'altezza del rettangolo, provare a impostare i valori locali iniziali che differiscono da qualsiasi From valore. Le animazioni di esempio iniziano subito usando il From valore anziché il valore di base. Se si Stop specifica come , al completamento un'animazione FillBehaviorreimposta il valore di una proprietà sul valore di base. La precedenza normale viene usata per determinare il valore di base dopo la fine di un'animazione.

È possibile applicare più animazioni a una singola proprietà, con ogni animazione con precedenza diversa. Invece di applicare l'animazione con la precedenza più alta, il motore di presentazione WPF potrebbe comporre i valori di animazione, a seconda della modalità di definizione delle animazioni e del tipo di valori animati. Per altre informazioni, vedere Cenni preliminari sull'animazione.

La coercizione è nella parte superiore dell'elenco di precedenza. Anche un'animazione in esecuzione è soggetta alla coercizione del valore. Alcune proprietà di dipendenza esistenti in WPF hanno coercizione predefinita. Per le proprietà di dipendenza personalizzate, è possibile definire il comportamento di coercizione scrivendo un oggetto CoerceValueCallback passato come parte dei metadati quando si crea una proprietà. È anche possibile eseguire l'override del comportamento di coercizione delle proprietà esistenti eseguendo l'override dei metadati per tale proprietà in una classe derivata. La coercizione interagisce con il valore di base in modo che i vincoli sulla coercizione vengano applicati così come esistono al momento, ma il valore di base viene mantenuto. Di conseguenza, se i vincoli nella coercizione vengono successivamente revocati, la coercizione restituirà il valore più vicino possibile al valore di base e potenzialmente l'influenza della coercizione su una proprietà cesserà non appena vengono revocati tutti i vincoli. Per altre informazioni sul comportamento di coercizione, vedere Callback e convalida delle proprietà di dipendenza.

Comportamenti dei trigger

I controlli spesso definiscono i comportamenti dei trigger come parte del relativo stile predefinito. L'impostazione delle proprietà locali nei controlli può potenzialmente essere in conflitto con tali trigger, impedendo ai trigger di rispondere (visivamente o comportamentalmente) agli eventi guidati dall'utente. Un uso comune di un trigger di proprietà consiste nel controllare le proprietà dello stato, ad esempio IsSelected o IsEnabled. Ad esempio, per impostazione predefinita, quando un oggetto Button è disabilitato, un trigger dello stile del tema (IsEnabled è false) imposta il Foreground valore per rendere l'oggetto Button visualizzato in grigio. Se è stato impostato un valore locale Foreground , il valore della proprietà locale con precedenza superiore sovrarulerà il valore dello stile Foreground del tema, anche quando Button è disabilitato. Quando si impostano i valori delle proprietà che eseguono l'override dei comportamenti dei trigger a livello di tema per un controllo, prestare attenzione a non interferire eccessivamente con l'esperienza utente desiderata per tale controllo.

ClearValue

Il ClearValue metodo cancella qualsiasi valore applicato localmente di una proprietà di dipendenza per un elemento. Tuttavia, la chiamata ClearValue non garantisce che il valore predefinito stabilito nei metadati durante la registrazione della proprietà sia il nuovo valore effettivo. Tutti gli altri partecipanti nell'elenco di precedenza sono ancora attivi e viene rimosso solo il valore impostato in locale. Ad esempio, se si chiama ClearValue su una proprietà con uno stile del tema, il valore dello stile del tema verrà applicato come nuovo valore anziché come valore predefinito basato sui metadati. Se si vuole impostare un valore della proprietà sul valore predefinito dei metadati registrati, ottenere il valore dei metadati predefinito eseguendo una query sui metadati della proprietà di dipendenza e impostando localmente il valore della proprietà con una chiamata a SetValue.

Vedi anche