Panoramica delle risorse XAML
Una risorsa è un oggetto che può essere riutilizzato in posizioni diverse nell'app. Esempi di risorse sono pennelli e stili. Questa panoramica descrive come usare le risorse in XAML (Extensible Application Markup Language). È anche possibile creare e accedere alle risorse usando il codice.
Nota
Le risorse XAML descritte in questo articolo sono diverse da risorse dell'app che sono in genere file aggiunti a un'app, ad esempio contenuto, dati o file incorporati.
Uso delle risorse in XAML
Nell'esempio seguente viene definito un SolidColorBrush come risorsa nell'elemento radice di una pagina. L'esempio fa quindi riferimento alla risorsa e la usa per impostare le proprietà di diversi elementi figlio, tra cui un Ellipse, un TextBlocke un Button.
<Page Name="root"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
>
<Page.Resources>
<SolidColorBrush x:Key="MyBrush" Color="Gold"/>
<Style TargetType="Border" x:Key="PageBackground">
<Setter Property="Background" Value="Blue"/>
</Style>
<Style TargetType="TextBlock" x:Key="TitleText">
<Setter Property="Background" Value="Blue"/>
<Setter Property="DockPanel.Dock" Value="Top"/>
<Setter Property="FontSize" Value="18"/>
<Setter Property="Foreground" Value="#4E87D4"/>
<Setter Property="FontFamily" Value="Trebuchet MS"/>
<Setter Property="Margin" Value="0,40,10,10"/>
</Style>
<Style TargetType="TextBlock" x:Key="Label">
<Setter Property="DockPanel.Dock" Value="Right"/>
<Setter Property="FontSize" Value="8"/>
<Setter Property="Foreground" Value="{StaticResource MyBrush}"/>
<Setter Property="FontFamily" Value="Arial"/>
<Setter Property="FontWeight" Value="Bold"/>
<Setter Property="Margin" Value="0,3,10,0"/>
</Style>
</Page.Resources>
<StackPanel>
<Border Style="{StaticResource PageBackground}">
<DockPanel>
<TextBlock Style="{StaticResource TitleText}">Title</TextBlock>
<TextBlock Style="{StaticResource Label}">Label</TextBlock>
<TextBlock DockPanel.Dock="Top" HorizontalAlignment="Left" FontSize="36" Foreground="{StaticResource MyBrush}" Text="Text" Margin="20" />
<Button DockPanel.Dock="Top" HorizontalAlignment="Left" Height="30" Background="{StaticResource MyBrush}" Margin="40">Button</Button>
<Ellipse DockPanel.Dock="Top" HorizontalAlignment="Left" Width="100" Height="100" Fill="{StaticResource MyBrush}" Margin="40" />
</DockPanel>
</Border>
</StackPanel>
</Page>
Ogni elemento a livello di framework (FrameworkElement o FrameworkContentElement) ha una proprietà Resources, ovvero un tipo di ResourceDictionary che contiene risorse definite. È possibile definire le risorse in qualsiasi elemento, ad esempio un Button. Tuttavia, le risorse vengono spesso definite nell'elemento radice, che è Page nell'esempio.
Ogni risorsa in un dizionario risorse deve avere una chiave univoca. Quando si definiscono le risorse nel markup, si assegna la chiave univoca tramite la direttiva x:Key . In genere, la chiave è una stringa; Tuttavia, è anche possibile impostarlo su altri tipi di oggetto usando le estensioni di markup appropriate. Le chiavi non di tipo stringa per le risorse vengono usate da determinate aree di funzionalità in WPF, in particolare per gli stili, le risorse dei componenti e lo stile dei dati.
È possibile usare una risorsa definita con la sintassi dell'estensione di markup delle risorse che specifica il nome della chiave della risorsa. Ad esempio, usare la risorsa come valore di una proprietà su un altro elemento.
<Button Background="{StaticResource MyBrush}"/>
<Ellipse Fill="{StaticResource MyBrush}"/>
Nell'esempio precedente, quando il caricatore XAML elabora il valore {StaticResource MyBrush}
per la proprietà Background in Button, la logica di ricerca della risorsa controlla innanzitutto il dizionario risorse per l'elemento Button. Se Button non ha una definizione della chiave di risorsa MyBrush
(in questo esempio non lo è; la raccolta di risorse è vuota), la ricerca successiva controlla l'elemento padre di Button, che è Page. Se si definisce una risorsa nell'elemento radice Page, tutti gli elementi nell'albero logico del Page possono accedervi. È anche possibile riutilizzare la stessa risorsa per impostare il valore di qualsiasi proprietà che accetta lo stesso tipo rappresentato dalla risorsa. Nell'esempio precedente, la stessa risorsa MyBrush
imposta due proprietà diverse: la Background di un Buttone la Fill di un Rectangle.
Risorse statiche e dinamiche
È possibile fare riferimento a una risorsa come statica o dinamica. I riferimenti vengono creati usando l'Estensione di Markup StaticResource o l'Estensione di Markup DynamicResource . Un'estensione di markup è una funzionalità di XAML che consente di specificare un riferimento a un oggetto elaborando la stringa dell'attributo con l'estensione di markup e restituendo l'oggetto a un caricatore XAML. Per ulteriori informazioni sul comportamento delle estensioni di markup, vedere Markup Extensions e WPF XAML.
Quando si usa un'estensione di markup, in genere si forniscono uno o più parametri in formato stringa elaborati da tale estensione di markup specifica. L'StaticResource Markup Extension elabora una chiave cercando il valore di tale chiave in tutti i dizionari risorse disponibili. L'elaborazione avviene durante il caricamento, ovvero quando il processo di caricamento deve assegnare il valore della proprietà. Il DynamicResource Markup Extension elabora invece una chiave creando un'espressione e tale espressione rimane non valutata fino all'esecuzione dell'app, in cui l'espressione viene valutata e fornisce un valore.
Quando si fa riferimento a una risorsa, le considerazioni seguenti possono influire sull'uso di un riferimento a una risorsa statica o di un riferimento a una risorsa dinamica:
Quando si determina la progettazione complessiva della modalità di creazione delle risorse per l'app (per pagina, nell'app, in XAML libero o in un assembly di sola risorsa), tenere presente quanto segue:
Funzionalità dell'app. L'aggiornamento delle risorse in tempo reale fa parte dei requisiti dell'app?
Comportamento di ricerca corrispondente del tipo di riferimento della risorsa.
La proprietà o il tipo di risorsa specifico e il comportamento nativo di questi tipi.
Risorse statiche
I riferimenti alle risorse statiche funzionano meglio per le circostanze seguenti:
La progettazione dell'app concentra la maggior parte delle risorse in dizionari di risorse a livello di pagina o di applicazione. I riferimenti alle risorse statiche non vengono rivalutati in base ai comportamenti di runtime, ad esempio ricaricando una pagina. È quindi possibile ottenere alcuni vantaggi in merito alle prestazioni per evitare un numero elevato di riferimenti dinamici alle risorse quando non sono necessari in base alla progettazione di risorse e app.
Stai impostando il valore di una proprietà che non si trova su un DependencyObject o un Freezable.
Si sta creando un dizionario risorse che verrà compilato in una DLL e inserito in un pacchetto come parte dell'app o condiviso tra le app.
Si sta creando un tema per un controllo personalizzato e si definiscono le risorse usate all'interno dei temi. Per questo caso, in genere non si desidera il comportamento di ricerca delle risorse dinamiche; si preferisce invece il comportamento di riferimento delle risorse statiche, in modo che la ricerca sia prevedibile e autonoma all'interno del tema. Con un riferimento di risorsa dinamica, anche un riferimento all'interno di un tema rimane non valutato fino al momento dell'esecuzione. e c'è una possibilità che quando viene applicato il tema, qualche elemento locale ridefinisca una chiave a cui il tema sta cercando di fare riferimento e l'elemento locale apparirà prima del tema stesso nella ricerca. In questo caso, il tuo tema non si comporterà come previsto.
Si usano risorse per impostare un numero elevato di proprietà di dipendenza. Le proprietà di dipendenza hanno la memorizzazione nella cache del valore effettivo, abilitata dal sistema delle proprietà. Pertanto, se si fornisce un valore per una proprietà di dipendenza valutabile in fase di caricamento, la proprietà di dipendenza non deve rivalutare l'espressione e può restituire l'ultimo valore effettivo. Questa tecnica può essere un vantaggio per le prestazioni.
Si vuole modificare la risorsa sottostante per tutti i consumer oppure mantenere istanze scrivibili separate per ogni consumer usando l'attributo x:Shared.
Comportamento di ricerca delle risorse statiche
Di seguito viene descritto il processo di ricerca che si verifica automaticamente quando una risorsa statica fa riferimento a una proprietà o a un elemento:
Il processo di ricerca controlla la chiave richiesta all'interno del dizionario delle risorse definito dall'elemento che definisce la proprietà.
Il processo di ricerca percorre quindi l'albero logico verso l'alto fino a raggiungere l'elemento padre e il suo dizionario delle risorse. Questo processo continua finché non viene raggiunto l'elemento radice.
Vengono controllate le risorse dell'app. Le risorse dell'app sono quelle all'interno del dizionario delle risorse definito dall'oggetto Application per la tua app WPF.
I riferimenti di risorse statici dall'interno di un dizionario risorse devono fare riferimento a una risorsa già definita in modo lessicale prima del riferimento alla risorsa. I riferimenti in avanti non possono essere risolti da un riferimento a una risorsa statica. Progetta la struttura del dizionario delle risorse affinché le risorse siano definite all'inizio o nei pressi di ogni rispettivo dizionario delle risorse.
La ricerca di risorse statiche può estendersi in temi o in risorse di sistema, ma questa ricerca è supportata solo perché il caricatore XAML rinvia la richiesta. Il rinvio è necessario affinché il tema di runtime al momento del caricamento della pagina sia applicato correttamente all'applicazione. Tuttavia, i riferimenti statici alle risorse con chiavi note per esistere solo nei temi o come risorse di sistema non sono consigliati, perché tali riferimenti non vengono aggiornati se il tema viene modificato dall'utente in tempo reale. Un riferimento di risorsa dinamica è più affidabile quando si richiedono risorse di sistema o tema. L'eccezione è quando un elemento tema stesso richiede un'altra risorsa. Questi riferimenti devono essere riferimenti a risorse statiche, per i motivi indicati in precedenza.
Il comportamento dell'eccezione se non viene trovato un riferimento a una risorsa statica varia. Se la risorsa è stata posticipata, l'eccezione si verifica in fase di esecuzione. Se la risorsa non è stata posticipata, l'eccezione si verifica in fase di caricamento.
Risorse dinamiche
Le risorse dinamiche funzionano meglio quando:
Il valore della risorsa, incluse le risorse di sistema o le risorse che altrimenti sono impostabili dall'utente, dipende dalle condizioni che non sono note fino al runtime. Ad esempio, è possibile creare valori setter che fanno riferimento alle proprietà di sistema esposte da SystemColors, SystemFontso SystemParameters. Questi valori sono realmente dinamici perché provengono dall'ambiente di runtime dell'utente e del sistema operativo. È anche possibile che siano presenti temi a livello di applicazione che possono cambiare, in cui l'accesso alle risorse a livello di pagina deve anche acquisire la modifica.
Si stanno creando o facendo riferimento agli stili del tema per un controllo personalizzato.
Si intende modificare il contenuto di un ResourceDictionary durante la durata di un'app.
Si dispone di una struttura di risorse complessa con interdipendenze, in cui potrebbe essere necessario un riferimento in avanti. I riferimenti a risorse statiche non supportano i riferimenti in avanti, ma i riferimenti dinamici alle risorse supportano tali riferimenti, perché la risorsa non deve essere valutata fino al runtime e i riferimenti inoltrati non sono quindi un concetto pertinente.
Si fa riferimento a una risorsa di grandi dimensioni dal punto di vista di una compilazione o di un working set e la risorsa potrebbe non essere usata immediatamente quando la pagina viene caricata. I riferimenti alle risorse statiche vengono sempre caricati da XAML quando la pagina viene caricata. Tuttavia, un riferimento di risorsa dinamica non viene caricato fino a quando non viene usato.
Si sta creando uno stile in cui i valori di setter possono provenire da altri valori influenzati dai temi o da altre impostazioni utente.
Si stanno applicando risorse a elementi che potrebbero essere ricollocati nell'albero logico durante il ciclo di vita dell'app. Modificare l'elemento padre cambia anche potenzialmente l'ambito di ricerca delle risorse, quindi se si desidera che la risorsa per un elemento riassegnato venga rivalutata in base al nuovo ambito, utilizzare sempre un riferimento dinamico per la risorsa.
Comportamento di ricerca delle risorse dinamiche
Il comportamento di ricerca delle risorse per un riferimento di risorsa dinamica è parallela a quello nel tuo codice come se chiami FindResource o SetResourceReference:
La ricerca controlla la chiave richiesta all'interno del dizionario delle risorse definito dall'elemento che imposta la proprietà:
Se l'elemento definisce una proprietà Style, il System.Windows.FrameworkElement.Style dell'elemento viene verificato nel relativo dizionario Resources.
Se l'elemento definisce una proprietà Template, viene controllato il dizionario System.Windows.FrameworkTemplate.Resources dell'elemento.
La ricerca attraversa l'albero logico in senso ascendente fino all'elemento padre e al relativo dizionario risorse. Questo processo continua finché non viene raggiunto l'elemento radice.
Vengono controllate le risorse dell'app. Le risorse dell'app si riferiscono a quelle risorse all'interno del dizionario delle risorse definite dall'oggetto Application per la tua app WPF.
Il dizionario risorse del tema viene controllato per il tema attualmente attivo. Se il tema cambia in fase di esecuzione, il valore viene rivalutato.
Vengono controllate le risorse di sistema.
Il comportamento dell'eccezione (se presente) varia:
Se una risorsa è stata richiesta da una chiamata FindResource e non è stata trovata, viene generata un'eccezione.
Se una risorsa è stata richiesta da una chiamata TryFindResource e non è stata trovata, non viene generata alcuna eccezione e il valore restituito viene
null
. Se la proprietà impostata non accettanull
, è comunque possibile che venga generata un'eccezione più grave, a seconda della proprietà specifica impostata.Se una risorsa è stata richiesta da un riferimento di risorsa dinamica in XAML e non è stata trovata, il comportamento dipende dal sistema di proprietà generale. Il comportamento generale è come se non si verificasse alcuna operazione di impostazione della proprietà a livello in cui esiste la risorsa. Ad esempio, se si tenta di impostare lo sfondo su un singolo elemento pulsante usando una risorsa che non è stato possibile valutare, non viene impostato alcun valore, ma il valore effettivo può comunque provenire da altri partecipanti nel sistema di proprietà e precedenza del valore. Ad esempio, il valore di sfondo potrebbe comunque provenire da uno stile di pulsante definito localmente o dallo stile del tema. Per le proprietà non definite dagli stili del tema, il valore effettivo dopo una valutazione delle risorse non riuscita potrebbe provenire dal valore predefinito nei metadati della proprietà.
Restrizioni
I riferimenti alle risorse dinamiche presentano alcune restrizioni rilevanti. Almeno una delle condizioni seguenti deve essere vera:
La proprietà impostata deve essere una proprietà di un FrameworkElement o FrameworkContentElement. Tale proprietà deve essere supportata da un DependencyProperty.
Il riferimento si riferisce a un valore all'interno di un
StyleSetter
.La proprietà impostata deve essere una proprietà di un Freezable fornito come valore di una proprietà FrameworkElement o FrameworkContentElement oppure un valore Setter.
Poiché la proprietà impostata deve essere una proprietà DependencyProperty o Freezable, la maggior parte delle modifiche alle proprietà può essere propagata all'interfaccia utente perché una modifica della proprietà (il valore della risorsa dinamica modificata) viene riconosciuta dal sistema di proprietà. La maggior parte dei controlli ha una logica che forza un nuovo layout di un controllo nel caso in cui un DependencyProperty cambi e tale proprietà influisca sul layout. Tuttavia, non tutte le proprietà che hanno un DynamicResource Markup Extension come valore garantiscono aggiornamenti in tempo reale nell'interfaccia utente. Tale funzionalità potrebbe comunque variare a seconda della proprietà, nonché a seconda del tipo proprietario della proprietà o anche della struttura logica dell'app.
Stili, datatemplate e chiavi implicite
Anche se tutti gli elementi di un ResourceDictionary devono avere una chiave, ciò non significa che tutte le risorse devono avere un x:Key
esplicito. Diversi tipi di oggetto supportano una chiave implicita quando definita come risorsa, in cui il valore della chiave è associato al valore di un'altra proprietà. Questo tipo di chiave è noto come chiave implicita, mentre un attributo x:Key
è una chiave esplicita. È possibile sovrascrivere qualsiasi chiave implicita specificando una chiave esplicita.
Uno scenario importante per le risorse è quando si definisce un Style. Infatti, un Style è quasi sempre definito come una voce in un dizionario delle risorse, perché gli stili sono intrinsecamente destinati per il riutilizzo. Per ulteriori informazioni sugli stili, vedere Styling e Templating.
Gli stili per i controlli possono essere creati e avere riferimento tramite una chiave implicita. Gli stili del tema che definiscono l'aspetto predefinito di un controllo si basano su questa chiave implicita. Dal punto di vista della richiesta, la chiave implicita è la Type del controllo stesso. Dal punto di vista della definizione delle risorse, la chiave implicita è la TargetType dello stile. Pertanto, se si creano temi per controlli personalizzati o si creano stili che interagiscono con gli stili del tema esistenti, non è necessario specificare un x:Key Directive per tale Style. E se si desidera utilizzare gli stili con tema, non è necessario specificare alcuno stile. Ad esempio, la definizione di stile seguente funziona anche se la risorsa Style non sembra avere una chiave:
<Style TargetType="Button">
<Setter Property="Background">
<Setter.Value>
<LinearGradientBrush>
<GradientStop Offset="0.0" Color="AliceBlue"/>
<GradientStop Offset="1.0" Color="Salmon"/>
</LinearGradientBrush>
</Setter.Value>
</Setter>
<Setter Property="FontSize" Value="18"/>
</Style>
Questo stile ha davvero una chiave: la chiave implicita typeof(System.Windows.Controls.Button)
. Nel markup è possibile specificare un TargetType direttamente come nome del tipo oppure, facoltativamente, usare {x:Type...} per restituire un Type.
Tramite i meccanismi di stile del tema predefiniti usati da WPF, tale stile viene applicato come stile di runtime di un Button nella pagina, anche se il Button stesso non tenta di specificare la relativa proprietà Style o un riferimento di risorsa specifico allo stile. Lo stile definito nella pagina viene trovato in precedenza nella sequenza di ricerca rispetto allo stile del dizionario dei temi, usando la stessa chiave dello stile del dizionario dei temi. È sufficiente specificare <Button>Hello</Button>
in qualsiasi punto della pagina e lo stile definito con TargetType di Button
si applica a tale pulsante. Se si desidera, è comunque possibile chiavere in modo esplicito lo stile con lo stesso valore del tipo TargetType per maggiore chiarezza nel markup, ma questo è facoltativo.
Le chiavi implicite per gli stili non si applicano a un elemento di controllo se OverridesDefaultStyle è true
. Si noti anche che OverridesDefaultStyle potrebbe essere impostato come parte del comportamento nativo per la classe di controllo, anziché in modo esplicito in un'istanza del controllo. Inoltre, per supportare chiavi implicite per gli scenari di classi derivate, il controllo deve eseguire l'override di DefaultStyleKey (tutti i controlli esistenti forniti come parte di WPF includono questa override). Per altre informazioni su stili, temi e progettazione dei controlli, vedere linee guida per la progettazione di controlli stilizzabili.
DataTemplate ha anche una chiave implicita. La chiave implicita per un DataTemplate è il valore della proprietà DataType. DataType può essere specificato anche come nome del tipo anziché usare in modo esplicito {x:Type...}. Per informazioni dettagliate, vedere Panoramica sui modelli di dati.
Vedere anche
.NET Desktop feedback