Condividi tramite


Cenni preliminari sulle risorse

In questi cenni preliminari viene spiegato come utilizzare le risorse di WPF come semplice metodo per riutilizzare oggetti e valori comunemente definiti. Viene inoltre puntata l'attenzione su come utilizzare le risorse in XAML. È inoltre possibile creare e accedere alle risorse tramite il codice o in modo intercambiabile tra codice e Extensible Application Markup Language (XAML). Per ulteriori informazioni, vedere Risorse e codice.

Nel presente argomento sono contenute le seguenti sezioni.

  • Utilizzo delle risorse in XAML
  • Risorse statiche e dinamiche
  • Stili, modelli di dati e chiavi implicite
  • Argomenti correlati

Utilizzo delle risorse in XAML

Nell'esempio riportato di seguito SolidColorBrush viene definito come risorsa nell'elemento radice di una pagina. Nell'esempio viene poi fatto riferimento alla risorsa che viene utilizzata per impostare le proprietà di numerosi elementi figlio, quali Ellipse, TextBlock e Button.

<Page Name="root"
  xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="https://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) dispone di una proprietà Resources, che rappresenta la proprietà contenente le risorse (come ResourceDictionary) definite da una risorsa. È possibile definire risorse per ogni elemento. Tuttavia le risorse vengono più spesso definite in relazione all'elemento radice, che nell'esempio in esame è Page.

Ogni risorsa di un dizionario risorse deve avere una chiave univoca. Quando si definiscono le risorse nel markup, si assegna la chiave univoca attraverso l'Direttiva x:Key. In genere la chiave è una stringa, ma è anche possibile impostarla su altri tipi di oggetti mediante le estensioni di markup appropriate. Le chiavi non di tipo stringa per le risorse vengono utilizzate da alcune aree di funzionalità in WPF, in particolare per stili, risorse dei componenti e applicazione di stili ai dati.

Dopo avere definito una risorsa, è possibile fare riferimento alla risorsa da utilizzare per il valore di una proprietà utilizzando una sintassi delle estensioni di markup delle risorse che specifichi il nome della chiave, ad esempio:

<Button Background="{StaticResource MyBrush}"/>
<Ellipse Fill="{StaticResource MyBrush}"/>

Nell'esempio precedente, quando il caricatore XAML elabora il valore {StaticResource MyBrush} per la proprietà Background relativa a Button, la logica di ricerca della risorsa verifica la presenza dell'elemento Button prima nel dizionario risorse. Se Button non dispone di una definizione della chiave della risorsa MyBrush (non ne dispone; l'insieme di risorse relative è vuoto), la verifica prosegue alla ricerca dell'elemento padre di Button, vale a dire Page. Di conseguenza, quando si definisce una risorsa in relazione all'elemento radice Page, tutti gli elementi della struttura ad albero logica di Page possono accedervi ed è possibile riutilizzare la stessa risorsa per impostare il valore di qualsiasi proprietà che accetti l'oggetto Type che la risorsa rappresenta. Nell'esempio precedente la stessa risorsa MyBrush imposta due diverse proprietà, vale a dire Background di Button e Fill di Rectangle.

Risorse statiche e dinamiche

Si può fare riferimento a una risorsa come statica o dinamica. Questa operazione viene eseguita utilizzando l'Estensione del markup StaticResource o l'Estensione del markup DynamicResource. Un'estensione di markup è una funzionalità di XAML per cui è possibile specificare un riferimento a un oggetto facendo in modo che l'estensione di markup elabori la stringa dell'attributo e restituisca l'oggetto a un caricatore XAML. Per ulteriori informazioni sul comportamento delle estensioni di markup, vedere Estensioni di markup e XAML WPF.

Quando si utilizza un'estensione di markup, si fornisce in genere uno o più parametri sotto forma di stringa che vengono elaborati dalla particolare estensione di markup, invece di essere valutati nel contesto della proprietà che viene impostata. L'Estensione del markup StaticResource consente di elaborare una chiave cercando il valore di tale chiave in tutti i dizionari risorse disponibili. Ciò si verifica durante il caricamento, il momento in cui il processo di caricamento deve assegnare il valore della proprietà che richiede il riferimento alla risorsa statica. L'Estensione del markup DynamicResource consente invece di elaborare una chiave creando un'espressione che non viene valutata fino all'esecuzione effettiva dell'applicazione, momento in cui l'espressione fornisce anche un valore.

Quando si fa riferimento a una risorsa, le considerazioni riportate di seguito possono influire sull'utilizzo di un riferimento a una risorsa statica o dinamica:

  • La progettazione globale del modo in cui si creano le risorse per l'applicazione (per pagina, nell'applicazione, in XAML separato, in un assembly di sole risorse).

  • La funzionalità dell'applicazione: l'aggiornamento delle risorse in tempo reale è parte dei requisiti dell'applicazione?

  • Il comportamento di ricerca relativo a tale tipo di riferimento della risorsa.

  • La particolare proprietà o tipo di risorsa e il comportamento nativo di questi tipi.

Risorse statiche

I riferimenti alle risorse statiche funzionano meglio nelle seguenti circostanze:

  • La progettazione dell'applicazione si concentra per lo più sulle risorse nei dizionari risorse a livello di pagina o di applicazione. I riferimenti alle risorse statiche non vengono rivalutati in base ai comportamenti in fase di esecuzione come nel caso di un nuovo caricamento della pagina e, di conseguenza, ne potrebbero derivare alcuni vantaggi in termini di prestazioni evitando numerosi riferimenti alle risorse dinamiche quando non sono necessari per la risorsa e la progettazione dell'applicazione.

  • Viene impostato il valore di una proprietà che non si trova in un oggetto DependencyObject o Freezable.

  • Si crea un dizionario risorse che verrà compilato in una DLL e compresso come parte dell'applicazione o condiviso tra le applicazioni.

  • Si crea un tema per un controllo personalizzato e si definiscono le risorse utilizzate all'interno dei temi. In questo caso, in genere, non si desidera il comportamento di ricerca dei riferimenti alle risorse dinamiche, ma il comportamento relativo ai riferimenti alle risorse statiche per fare in modo che la ricerca sia prevedibile e indipendente in relazione al tema. Con un riferimento alla risorsa dinamica, anche un riferimento all'interno di un tema rimane non valutato fino alla fase di esecuzione ed esiste la possibilità che al momento dell'applicazione del tema, alcuni elementi locali ridefiniranno una chiave a cui il tema sta cercando di fare riferimento e l'elemento locale precederà il tema stesso nella ricerca. Se si verifica tale evenienza, il comportamento del tema non sarà quello previsto.

  • Si utilizzano le risorse per impostare numerose proprietà di dipendenza. Le proprietà di dipendenza dispongono dell'archiviazione efficace dei valori abilitata dal sistema di proprietà, pertanto se si fornisce un valore per una proprietà di dipendenza che possa essere valutato al momento del caricamento, la proprietà di dipendenza non deve verificare un'espressione rivalutata e può restituire l'ultimo valore effettivo. Questa tecnica può rappresentare un vantaggio in termini di prestazioni.

  • Si desidera modificare la risorsa sottostante per tutti i consumer o si desidera mantenere istanze scrivibili separate per ciascun consumer mediante l'Attributo x:Shared.

Comportamento di ricerca delle risorse statiche

  1. Il processo di ricerca verifica la chiave richiesta all'interno del dizionario risorse definito dell'elemento che imposta la proprietà.

  2. Il processo di ricerca attraversa quindi la struttura ad albero logica verso l'alto, passando all'elemento padre e al dizionario risorse relativo. Il processo continua fino al raggiungimento dell'elemento radice.

  3. Successivamente vengono verificate le risorse dell'applicazione. Si tratta delle risorse all'interno del dizionario risorse definito dall'oggetto Application per l'applicazione WPF.

I riferimenti alle risorse statiche dall'interno di un dizionario risorse devono fare riferimento a una risorsa che sia già stata definita a livello lessicale prima del riferimento alla risorsa. I riferimenti in avanti non possono essere risolti da un riferimento a una risorsa statica. Per questo motivo, se si utilizzano riferimenti alle risorse statiche, è necessario progettare la struttura del dizionario risorse per fare in modo che le risorse destinate all'utilizzo da parte delle risorse vengano definite all'inizio o quasi di ogni dizionario risorse corrispondente.

La ricerca delle risorse statiche può estendersi ai temi o alle risorse di sistema, ma ciò è supportato solo perché il caricatore XAML rimanda la richiesta. Il rinvio è necessario per fare in modo che il tema in fase di esecuzione al momento del caricamento della pagina venga applicato in modo appropriato all'applicazione. Tuttavia non sono consigliati i riferimenti alle risorse statiche alle chiavi che è noto esistono solo nei temi o come risorse di sistema, perché tali riferimenti non vengono rivalutati se il tema viene modificato dall'utente in tempo reale. Un riferimento a una risorsa dinamica è più attendibile quando è necessario un tema o le risorse di sistema. L'eccezione avviene quando l'elemento relativo a un tema stesso richiede un'altra risorsa. Questi riferimenti devono essere relativi a risorse statiche, per i motivi menzionati in precedenza.

Il comportamento dell'eccezione relativo al mancato ritrovamento di un riferimento a una risorsa statica varia. Se la risorsa è stata rinviata, in fase di esecuzione viene generata l'eccezione. Se la risorsa non è stata rinviata, l'eccezione viene generata al momento del caricamento.

Risorse dinamiche

Le risorse dinamiche funzionano meglio nelle seguenti circostanze:

  • Il valore della risorsa dipende da condizioni che non sono note fino alla fase di esecuzione. Ciò comprende le risorse di sistema o le risorse che possono essere impostate dall'utente. È ad esempio possibile creare valori del metodo di impostazione che facciano riferimento alle proprietà di sistema, come esposto dall'oggetto SystemColors, SystemFonts o SystemParameters. Questi valori sono effettivamente dinamici perché in definitiva derivano dall'ambiente di runtime e dal sistema operativo dell'utente. Si potrebbero anche avere temi a livello di applicazione che possono cambiare, in cui anche l'accesso alla risorsa a livello di pagina deve acquisire la modifica.

  • Si creano o si fa riferimento a stili dei temi per un controllo personalizzato.

  • Si ha intenzione di adattare il contenuto di un oggetto ResourceDictionary durante il ciclo di vita di un'applicazione.

  • Si dispone di una struttura di risorse complicata con interdipendenze, in cui potrebbe essere necessario un riferimento in avanti. I riferimenti alle risorse statiche non supportano i riferimenti in avanti, ma quelli relativi alle risorse dinamiche li supportano perché la risorsa non deve essere valutata fino alla fase di esecuzione e i riferimenti in avanti non sono pertanto un concetto rilevante.

  • Si fa riferimento a una risorsa di dimensioni particolarmente grandi dal punto di vista di una compilazione o di un working set e la risorsa potrebbe non essere utilizzata immediatamente al momento del caricamento della pagina. I riferimenti alle risorse statiche vengono sempre caricati da XAML al momento del caricamento della pagina. Tuttavia un riferimento a una risorsa dinamica non viene caricato finché non viene effettivamente utilizzato.

  • Si crea uno stile in cui i valori del metodo di impostazione potrebbero derivare da altri valori sui quali influiscono i temi o altre impostazioni utente.

  • Si applicano le risorse agli elementi che potrebbero essere riassociati come elementi padre nella struttura ad albero logica nel ciclo di vita dell'applicazione. Modificando l'elemento padre si modifica potenzialmente anche l'ambito della ricerca delle risorse, per cui se si desidera che la risorsa per un elemento riassociato come padre venga rivalutata in base al nuovo ambito, utilizzare sempre un riferimento a una risorsa dinamica.

Comportamento di ricerca delle risorse dinamiche

Il comportamento di ricerca delle risorse per un riferimento a una risorsa dinamica è parallelo al comportamento di ricerca nel codice se si chiama FindResource o SetResourceReference.

  1. Il processo di ricerca verifica la chiave richiesta all'interno del dizionario risorse definito dall'elemento che imposta la proprietà.

  2. Il processo di ricerca attraversa quindi la struttura ad albero logica verso l'alto, passando all'elemento padre e al dizionario risorse relativo. Il processo continua fino al raggiungimento dell'elemento radice.

  3. Successivamente vengono verificate le risorse dell'applicazione. Si tratta delle risorse all'interno del dizionario risorse definito dall'oggetto Application per l'applicazione WPF.

  4. Il dizionario risorse dei temi viene controllato alla ricerca del tema correntemente attivo. Se il tema cambia in fase di esecuzione, il valore viene rivalutato.

  5. Vengono verificare le risorse di sistema.

Il comportamento di eccezione (se presente) varia:

  • Se è stata richiesta una risorsa da una chiamata FindResource che non è stata trovata, si genera un'eccezione.

  • Se è stata richiesta una risorsa da una chiamata TryFindResource che non è stata trovata, non si genera alcuna eccezione, ma il valore restituito è null. Se la proprietà che viene impostata non accetta il valore null, è ancora possibile che venga generata un'eccezione avanzata (ciò dipende dalla singola proprietà impostata).

  • Se una risorsa è stata richiesta da un riferimento a una risorsa dinamica in XAML e non è stata trovata, il comportamento dipende dal sistema di proprietà generale, ma il comportamento generale comporta che nessuna operazione di impostazione delle proprietà venga effettuata al livello in cui esiste la risorsa. Se, ad esempio, si tenta di impostare lo sfondo in un singolo elemento pulsante mediante una risorsa che non potrebbe essere valutata, nessun valore imposta i risultati, ma il valore effettivo può ancora derivare da altri partecipanti al sistema di proprietà e alla precedenza dei valori. Ad esempio il valore dello sfondo potrebbe ancora derivare da uno stile del pulsante definito localmente o dallo stile del tema. Per le proprietà che non sono definite dagli stili del tema, il valore effettivo dopo una valutazione di una risorsa non riuscita potrebbe derivare dal valore predefinito nei metadati della proprietà.

Restrizioni

I riferimenti alle risorse dinamiche hanno alcune restrizioni rilevanti. Almeno una delle seguenti restrizioni deve essere vera:

Dato che la proprietà che viene impostata deve essere una proprietà DependencyProperty o Freezable, la maggior parte delle modifiche relative deve propagarsi all'interfaccia utente perché una modifica alla proprietà (il valore della risorsa dinamica modificato) viene riconosciuta dal sistema di proprietà. La maggior parte dei controlli comprende una logica che impone un altro layout di un controllo se la proprietà DependencyProperty viene modificata e tale proprietà potrebbe influire sul layout. Tuttavia non è certo che tutte le proprietà che hanno un'Estensione del markup DynamicResource come valore forniscano il valore in modo tale per cui l'aggiornamento relativo viene effettuato in tempo reale nell'interfaccia utente. Tale funzionalità potrebbe ancora variare in base alla proprietà, oltre che al tipo proprietario della proprietà o persino in base alla struttura logica dell'applicazione.

Stili, modelli di dati e chiavi implicite

In precedenza è stato asserito che tutti gli elementi di ResourceDictionary devono avere una chiave. Tuttavia ciò non significa che tutte le risorse devono avere un attributo x:Key esplicito. Numerosi tipi di oggetti supportano una chiave implicita quando definiti come risorsa, dove il valore della chiave è associato al valore di un'altra proprietà. Ciò è noto come chiave implicita, mentre un attributo x:Key è una chiave esplicita. È possibile sovrascrivere qualsiasi chiave implicita specificando una chiave esplicita.

Uno scenario molto importante per le risorse riguarda il caso in cui si definisce un oggetto Style. In realtà un oggetto Style è quasi sempre definito come voce del dizionario risorse, dato che gli stili sono implicitamente destinati al riutilizzo. Per ulteriori informazioni sugli stili, vedere Applicazione di stili e modelli.

Gli stili per i controlli possono essere creati ed è possibile farvi riferimento con una chiave implicita. Gli stili dei temi che definiscono l'aspetto predefinito di un controllo si basano su questa chiave implicita. La chiave implicita dal punto di vista della richiesta è l'oggetto Type del controllo stesso. La chiave implicita dal punto di vista della definizione della risorsa è l'oggetto TargetType dello stile. Se, pertanto, si creano temi per i controlli personalizzati, creando stili che interagiscono con gli stili dei temi esistenti, non è necessario specificare un Direttiva x:Key per l'oggetto Style. Se si desidera inoltre utilizzare gli stili dei temi, non è necessario specificare alcuno stile. Ad esempio, la definizione di stile riportata di seguito funziona anche se la risorsa Style non sembra disporre di 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>

Tale stile dispone effettivamente di una chiave, vale a dire la chiave implicita typeof(Button). Nel markup è possibile specificare direttamente un oggetto TargetType come nome del tipo oppure è possibile utilizzare facoltativamente {x:Type...} per restituire un oggetto Type.

Mediante i meccanismi relativi agli stili dei temi predefiniti utilizzati da WPF, tale stile viene applicato come stile di runtime di un oggetto Button nella pagina, anche se l'oggetto Button stesso non tenta di specificare la proprietà Style relativa o un riferimento a una risorsa specifico dello stile. Lo stile definito nella pagina viene rilevato nella sequenza di ricerca prima dello stile del dizionario dei temi, mediante la stessa chiave a disposizione dello stile del dizionario dei temi. Si potrebbe semplicemente specificare <Button>Hello</Button> in qualsiasi punto della pagina e lo stile definito con l'oggetto TargetType di Button si applicherebbe a tale pulsante. Se si desidera, è ancora possibile associare in modo esplicito a una chiave lo stile con lo stesso tipo di valore di TargetType, per chiarezza nel markup, ma si tratta di un'operazione facoltativa.

Le chiavi implicite per gli stili non si applicano a un controllo se OverridesDefaultStyle è true (si noti anche che OverridesDefaultStyle potrebbe essere impostato come parte del comportamento nativo per la classe del controllo, invece che in modo esplicito in un'istanza del controllo). Inoltre, per supportare le 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 consentono questa operazione). Per ulteriori informazioni sugli stili, sui temi e sulla progettazione dei controlli, vedere Linee guida per la progettazione di controlli a cui è possibile applicare degli stili.

DataTemplate dispone anche di una chiave implicita. La chiave implicita di DataTemplate è il valore della proprietà DataType. DataType può anche essere specificato come nome del tipo invece di utilizzare in modo esplicito {x:Type...}. Per informazioni dettagliate, vedere Cenni preliminari sui modelli di dati.

Vedere anche

Attività

Procedura: definire e fare riferimento a una risorsa

Riferimenti

Estensione del markup x:Type

ResourceDictionary

Estensione del markup StaticResource

Estensione del markup DynamicResource

Concetti

Ottimizzazione delle prestazioni: risorse di applicazioni

Risorse e codice

Cenni preliminari sulla gestione di applicazioni