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.
Prerequisiti
L'articolo presuppone una conoscenza di base delle proprietà di dipendenza e che tu 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.
Il sistema di proprietà di 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à Background del 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 proprietà Background
è impostata localmente su Red
. Tuttavia, lo stile implicito dichiarato nell'ambito del pulsante tenta di impostare la proprietà Background
su Blue
. Inoltre, quando il mouse è sul pulsante, il trigger nello stile implicito tenta di impostare la proprietà Background
su Yellow
. Ad eccezione della coercizione e dell'animazione, un valore di proprietà impostato localmente ha la precedenza più alta, quindi il pulsante sarà rosso, anche quando si passa il mouse sopra. Tuttavia, se si rimuove il valore impostato localmente dal pulsante, otterrà il relativo valore Background
dallo stile. All'interno di uno stile, i trigger hanno la precedenza, quindi il pulsante sarà giallo al passaggio del mouse e blu altrimenti. Nell'esempio viene sostituito il ControlTemplate predefinito del pulsante perché il modello predefinito ha un valore mouseover Background
codificato staticamente.
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. Prima viene elencata la precedenza più alta.
Coercizione del sistema di proprietà. Per ulteriori informazioni sulla coercizione, vedere Coercizione e animazioni.
animazioni attive o animazioni con un comportamento di blocco. Per avere un effetto pratico, un valore animato deve avere la precedenza sul valore di base (senza animazione), anche se il valore di base è stato impostato localmente. Per ulteriori informazioni, vedere Coercizione e animazioni.
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 SetValue usando una proprietà di un'istanza specifica. Un valore locale impostato tramite un'associazione o una risorsa avrà la stessa precedenza di un valore impostato direttamente.
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 dalla
TemplatedParent
, l'ordine di precedenza è:Trigger.
Set di proprietà, in genere tramite attributi XAML.
stili impliciti. Si applica solo alla proprietà Style. Il valore
Style
è qualsiasi risorsa di stile con un valore TargetType che corrisponde 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.Attivatori di stile. Un trigger di stile è un elemento di attivazione presente 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.
Inneschi del modello. Un trigger di modello è un trigger di un modello applicato direttamente o di un modello incorporato in uno stile. Lo stile deve esistere all'interno della pagina o dell'applicazione.
valori di setter di stile. Un valore setter di stile è un valore applicato da un Setter all'interno di uno stile. Lo stile deve esistere all'interno della pagina o dell'applicazione.
Stili predefiniti, noti anche come stili di tema . Per altre informazioni, vedere stili predefiniti (tema). All'interno di uno stile predefinito, l'ordine di precedenza è:
Trigger attivi.
Setter.
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 ulteriori informazioni, vedere l'ereditarietà del valore della proprietà .
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 ulteriori informazioni, vedere i 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 (TemplatoGenitore)
La precedenza TemplatedParent non si applica alle proprietà degli elementi dichiarati direttamente nel markup standard dell'applicazione. Il concetto di TemplatedParent
esiste solo per gli elementi figlio all'interno di un albero visivo che prendono vita tramite l'applicazione di un template. Quando il sistema di proprietà cerca nel modello specificato dal TemplatedParent
i valori delle proprietà di un elemento, esegue una ricerca nel modello che ha creato l'elemento. I valori delle proprietà del modello di TemplatedParent
funzionano 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 altre informazioni, vedere TemplatedParent.
Proprietà Style
Lo stesso ordine di precedenza si applica a tutte le proprietà di dipendenza, ad eccezione della proprietà Style. La proprietà Style
è unica in quanto non può essere stilizzata. Non è consigliabile forzare o animare la proprietà Style
(e animare la proprietà Style
richiederebbe una classe di animazione personalizzata). Di conseguenza, non si applicano tutti gli elementi di precedenza. Esistono solo tre modi per impostare la proprietà Style
:
Stile esplicito. La proprietà
Style
di un elemento viene impostata direttamente. Il valore della proprietàStyle
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 esempioStyle="{StaticResource myResourceKey}"
.Stile implicito. La proprietà
Style
di un elemento non è 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 tipoMyButton
anche seMyButton
è derivato daButton
. Il valore della proprietàStyle
ha la stessa precedenza dell'elemento 5 nell'elenco di precedenza . È possibile rilevare un valore di stile implicito chiamando il metodo DependencyPropertyHelper.GetValueSource, passando la proprietàStyle
e verificandoImplicitStyleReference
nei risultati.stile predefinito, noto anche come stile tema . La proprietà
Style
di un elemento non è impostata direttamente. Proviene invece dalla valutazione del tema in esecuzione effettuata dal motore di presentazione WPF. Prima del runtime, il valore della proprietàStyle
ènull
. Il valore della proprietàStyle
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 tema.
Il ControlTemplate è un elemento importante all'interno dello stile predefinito per un controllo.
ControlTemplate
è un valore setter per la proprietà Template dello 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 controllo Thumb, ovvero un componente ScrollBar.
Un controllo Thumb dispone di determinate proprietà personalizzabili. Il modello predefinito di un controllo Thumb
crea una struttura di base o una struttura ad albero visuale, con diversi componenti Border annidati per creare un aspetto smussato. All'interno del modello, le proprietà destinate a essere personalizzabili dalla classe Thumb
sono rese accessibili tramite TemplateBinding. Il modello predefinito per il controllo Thumb
ha varie proprietà del bordo che condividono un'associazione di modelli con proprietà quali 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 TemplateBinding
, allora il valore della proprietà non può essere modificato dagli stili perché non esiste un modo pratico per indirizzarla. 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 TargetType nelle relative definizioni. La valutazione del tema di runtime associa il TargetType
di uno stile predefinito alla proprietà DefaultStyleKey di un controllo. Al contrario, il modo in cui vengono ricercati gli stili impliciti utilizza il tipo effettivo del controllo. Il valore di DefaultStyleKey
viene ereditato dalle classi derivate, pertanto gli elementi derivati che potrebbero altrimenti non avere 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 DefaultStyleKey
nei metadati delle proprietà di dipendenza. Pertanto, se si desidera una rappresentazione visiva diversa per MyButton
, è possibile eseguire l'override dei metadati della proprietà di dipendenza per DefaultStyleKey
in MyButton
e quindi definire lo stile predefinito pertinente, incluso un modello, che verrà incluso nel pacchetto con il controllo MyButton
. Per altre informazioni, vedere Panoramica sull'autorialità dei controlli.
Risorsa dinamica
I riferimenti alle risorse dinamiche e le operazioni di associazione hanno la precedenza sulla posizione in cui sono impostate. 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 fino al 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 metodo ClearValue 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.
ImpostaValoreAttuale
Il metodo SetCurrentValue è 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 entrambe 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 sia i valori delle proprietà From che To per determinati comportamenti o se l'animazione torna deliberatamente al valore di base al completamento, il valore di base può influire sul valore animato. Per visualizzare questa operazione 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 valore From
. Le animazioni di esempio iniziano subito usando il valore From
anziché il valore di base. Se si specifica Stop come FillBehavior, al termine di un'animazione un valore della proprietà verrà reimpostato 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 panoramica dell'animazione .
La coercizione è in cima all'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 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 di default . 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 Button è disabilitato, un trigger di stile del tema (IsEnabled
è false
) imposta il valore Foreground per far apparire il Button
in grigio. Se hai impostato un valore di Foreground
locale, il valore della proprietà locale con precedenza superiore sovrasterà il valore Foreground
dello stile del tema, anche se il 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 metodo ClearValue 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 all'elenco di precedenza sono ancora attivi e viene rimosso solo il valore impostato in locale. Ad esempio, se chiami 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 desideri impostare un valore della proprietà al valore predefinito dei metadati registrati, ottieni il valore predefinito dei metadati interrogando i metadati della proprietà di dipendenza e imposta localmente il valore della proprietà con una chiamata a SetValue.
Vedere anche
.NET Desktop feedback