Riferimenti a ResourceDictionary e risorse XAML

Puoi definire l'interfaccia utente o le risorse della tua applicazione utilizzando XAML. Le risorse sono in genere definizioni di qualche oggetto che si prevede di utilizzare più di una volta. Per fare riferimento a una risorsa XAML in un secondo momento, devi specificare una chiave per una risorsa che si comporta come il suo nome. Puoi fare riferimento a una risorsa in tutta l'applicazione o da qualsiasi pagina XAML al suo interno. Puoi definire le tue risorse utilizzando un elemento ResourceDictionary dallo XAML di Windows Runtime. Poi, puoi fare riferimento alle tue risorse utilizzando un'estensione di markup StaticResource o ThemeResource.

Gli elementi XAML che potresti voler dichiarare più spesso come risorse XAML includono Style, ControlTemplate, componenti di animazione e sottoclassi Brush. Qui ti spieghiamo come definire un ResourceDictionary e le risorse con chiave e come le risorse XAML si relazionano con le altre risorse che definisci come parte della tua applicazione o del tuo pacchetto di applicazioni. Inoltre spieghiamo le funzioni avanzate dei dizionari di risorse come MergedDictionaries e ThemeDictionaries.

Prerequisiti

Una solida conoscenza del markup XAML. Si consiglia di leggere Panoramica di XAML.

Definire e utilizzare le risorse XAML

Le risorse XAML sono oggetti che vengono citati dal markup più di una volta. Le risorse sono definite in un ResourceDictionary, tipicamente in un file separato o all'inizio della pagina di markup, come in questo caso.

<Page
    x:Class="MSDNSample.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">

    <Page.Resources>
        <x:String x:Key="greeting">Hello world</x:String>
        <x:String x:Key="goodbye">Goodbye world</x:String>
    </Page.Resources>

    <TextBlock Text="{StaticResource greeting}" Foreground="Gray" VerticalAlignment="Center"/>
</Page>

In questo esempio:

  • <Page.Resources>…</Page.Resources>: definisce il dizionario risorse.
  • <x:String>: definisce la risorsa con la chiave "greeting".
  • {StaticResource greeting}: cerca la risorsa con la chiave "greeting", assegnata alla proprietà Text di TextBlock.

Nota Non confondere i concetti relativi a ResourceDictionary con l'azione di compilazione Resource, i file di risorse (.resw) o altre "risorse" che vengono discusse nel contesto della strutturazione del progetto di codice che produce il tuo pacchetto di applicazioni.

Le risorse non devono essere necessariamente stringhe; possono essere qualsiasi oggetto condivisibile, come stili, modelli, pennelli e colori. Tuttavia, i controlli, le forme e altri FrameworkElementnon sono condivisibili, quindi non possono essere dichiarati come risorse riutilizzabili. Per maggiori informazioni sulla condivisione, consulta la sezione Le risorse XAML devono essere condivisibili più avanti in questo argomento.

In questo caso, sia un pennello che una stringa sono dichiarati come risorse e utilizzati dai controlli di una pagina.

<Page
    x:Class="SpiderMSDN.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">

    <Page.Resources>
        <SolidColorBrush x:Key="myFavoriteColor" Color="green"/>
        <x:String x:Key="greeting">Hello world</x:String>
    </Page.Resources>

    <TextBlock Foreground="{StaticResource myFavoriteColor}" Text="{StaticResource greeting}" VerticalAlignment="Top"/>
    <Button Foreground="{StaticResource myFavoriteColor}" Content="{StaticResource greeting}" VerticalAlignment="Center"/>
</Page>

Tutte le risorse devono avere una chiave. Di solito la chiave è una stringa definita con x:Key="myString". Tuttavia, esistono alcuni altri modi per specificare una chiave:

  • Style e ControlTemplate richiedono TargetType e useranno TargetType come chiave se x:Key non è specificato. In questo caso, la chiave è l'oggetto Type vero e proprio, non una stringa. (Vedi esempi sotto)
  • Le risorse DataTemplate con TargetType useranno TargetType come chiave se x:Key non è specificato. In questo caso, la chiave è l'oggetto Type vero e proprio, non una stringa.
  • x:Name può essere utilizzato al posto di x:Key. Tuttavia, x:Name genera anche un codice dietro al campo della risorsa. Di conseguenza, x:Name è meno efficiente di x:Key perché questo campo deve essere inizializzato quando la pagina viene caricata.

L'estensione di markup StaticResource può recuperare risorse solo con un nome stringa (x:Key o x:Name). Il framework XAML, tuttavia, cerca anche risorse di stile implicite (ovvero quelle che usano TargetType invece di x:Key o x:Name) quando si tratta di decidere quale stile e modello usare per un controllo per cui non sono impostate le proprietà Style e ContentTemplate o ItemTemplate.

In questo esempio, Style ha la chiave implicita typeof(Button) e dato che il controllo Button nella parte inferiore della pagina non specifica una proprietà Style, viene cercato uno stile con la chiave typeof(Button):

<Page
    x:Class="MSDNSample.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">

    <Page.Resources>
        <Style TargetType="Button">
            <Setter Property="Background" Value="Red"/>
        </Style>
    </Page.Resources>
    <Grid>
       <!-- This button will have a red background. -->
       <Button Content="Button" Height="100" VerticalAlignment="Center" Width="100"/>
    </Grid>
</Page>

Per maggiori informazioni sugli stili impliciti e sul loro funzionamento, consulta Stilizzare i controlli e Modelli di controllo.

Cerca le risorse nel codice

Puoi accedere ai membri del dizionario delle risorse come a qualsiasi altro dizionario.

Avviso

Quando esegui la ricerca di una risorsa nel codice, vengono esaminate solo le risorse nel dizionario Page.Resources. A differenza dell'estensione di markup StaticResource, il codice non torna al dizionario Application.Resources se le risorse non vengono trovate nel primo dizionario.

 

Questo esempio mostra come recuperare la risorsa redButtonStyle dal dizionario delle risorse di una pagina:

<Page
    x:Class="MSDNSample.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">

    <Page.Resources>
        <Style TargetType="Button" x:Key="redButtonStyle">
            <Setter Property="Background" Value="red"/>
        </Style>
    </Page.Resources>
</Page>
    public sealed partial class MainPage : Page
    {
        public MainPage()
        {
            this.InitializeComponent();
            Style redButtonStyle = (Style)this.Resources["redButtonStyle"];
        }
    }
    MainPage::MainPage()
    {
        InitializeComponent();
        Windows::UI::Xaml::Style style = Resources().TryLookup(winrt::box_value(L"redButtonStyle")).as<Windows::UI::Xaml::Style>();
    }

Per cercare le risorse dell'applicazione dal codice, usa Application.Current.Resources per ottenere il dizionario delle risorse dell'applicazione, come mostrato qui.

<Application
    x:Class="MSDNSample.App"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:SpiderMSDN">
    <Application.Resources>
        <Style TargetType="Button" x:Key="appButtonStyle">
            <Setter Property="Background" Value="red"/>
        </Style>
    </Application.Resources>

</Application>
    public sealed partial class MainPage : Page
    {
        public MainPage()
        {
            this.InitializeComponent();
            Style appButtonStyle = (Style)Application.Current.Resources["appButtonStyle"];
        }
    }
    MainPage::MainPage()
    {
        InitializeComponent();
        Windows::UI::Xaml::Style style = Application::Current().Resources()
                                                               .TryLookup(winrt::box_value(L"appButtonStyle"))
                                                               .as<Windows::UI::Xaml::Style>();
    }

Puoi anche aggiungere una risorsa applicativa nel codice.

Ci sono due cose da tenere a mente quando si compie questa operazione.

  • Per prima cosa, devi aggiungere le risorse prima che qualsiasi pagina cerchi di utilizzarle.
  • In secondo luogo, non puoi aggiungere risorse nel costruttore dell'app.

Puoi evitare entrambi i problemi se aggiungi la risorsa nel metodo Application.OnLaunched in questo modo.

// App.xaml.cs
    
sealed partial class App : Application
{
    protected override void OnLaunched(LaunchActivatedEventArgs e)
    {
        Frame rootFrame = Window.Current.Content as Frame;
        if (rootFrame == null)
        {
            SolidColorBrush brush = new SolidColorBrush(Windows.UI.Color.FromArgb(255, 0, 255, 0)); // green
            this.Resources["brush"] = brush;
            // … Other code that VS generates for you …
        }
    }
}
// App.cpp

void App::OnLaunched(LaunchActivatedEventArgs const& e)
{
    Frame rootFrame{ nullptr };
    auto content = Window::Current().Content();
    if (content)
    {
        rootFrame = content.try_as<Frame>();
    }

    // Do not repeat app initialization when the Window already has content,
    // just ensure that the window is active
    if (rootFrame == nullptr)
    {
        Windows::UI::Xaml::Media::SolidColorBrush brush{ Windows::UI::ColorHelper::FromArgb(255, 0, 255, 0) };
        Resources().Insert(winrt::box_value(L"brush"), winrt::box_value(brush));
        // … Other code that VS generates for you …

Ogni FrameworkElement può avere un ResourceDictionary

FrameworkElement è una classe base da cui ereditano i controlli e ha una proprietà Resources. Quindi, puoi aggiungere un dizionario di risorse locali a qualsiasi FrameworkElement.

In questo caso, sia la pagina Page che Border hanno dizionari di risorse ed entrambi hanno una risorsa chiamata "saluto". Il TextBlock chiamato 'textBlock2' si trova all'interno del Border, quindi la sua ricerca di risorse si rivolge prima alle risorse del Border, poi alle risorse della Pagee infine alle risorse della Application. Il TextBlock sarà "Hola mundo".

Per accedere alle risorse di quell'elemento dal codice, usa la proprietà Resources di quell'elemento. Accedendo alle risorse di un FrameworkElement nel codice, piuttosto che nello XAML, si cercherà solo in quel dizionario, non nei dizionari dell'elemento genitore.

<Page
    x:Class="MSDNSample.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
    <Page.Resources>
        <x:String x:Key="greeting">Hello world</x:String>
    </Page.Resources>
    
    <StackPanel>
        <!-- Displays "Hello world" -->
        <TextBlock x:Name="textBlock1" Text="{StaticResource greeting}"/>

        <Border x:Name="border">
            <Border.Resources>
                <x:String x:Key="greeting">Hola mundo</x:String>
            </Border.Resources>
            <!-- Displays "Hola mundo" -->
            <TextBlock x:Name="textBlock2" Text="{StaticResource greeting}"/>
        </Border>

        <!-- Displays "Hola mundo", set in code. -->
        <TextBlock x:Name="textBlock3"/>
    </StackPanel>
</Page>

    public sealed partial class MainPage : Page
    {
        public MainPage()
        {
            this.InitializeComponent();
            textBlock3.Text = (string)border.Resources["greeting"];
        }
    }
    MainPage::MainPage()
    {
        InitializeComponent();
        textBlock3().Text(unbox_value<hstring>(border().Resources().TryLookup(winrt::box_value(L"greeting"))));
    }

Dizionari di risorse unite

Un dizionario delle risorse unito combina un dizionario delle risorse in un altro, di solito in un altro file.

Suggerimento Puoi creare un file dizionario delle risorse in Microsoft Visual Studio utilizzando l'opzione Add > New Item... > Resource Dictionary dal menu Project .

In questo caso, definisci un dizionario di risorse in un file XAML separato chiamato Dictionary1.xaml.

<!-- Dictionary1.xaml -->
<ResourceDictionary
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:MSDNSample">

    <SolidColorBrush x:Key="brush" Color="Red"/>

</ResourceDictionary>

Per utilizzare questo dizionario, devi unirlo al dizionario della tua pagina:

<Page
    x:Class="MSDNSample.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
    <Page.Resources>
        <ResourceDictionary>
            <ResourceDictionary.MergedDictionaries>
                <ResourceDictionary Source="Dictionary1.xaml"/>
            </ResourceDictionary.MergedDictionaries>

            <x:String x:Key="greeting">Hello world</x:String>

        </ResourceDictionary>
    </Page.Resources>

    <TextBlock Foreground="{StaticResource brush}" Text="{StaticResource greeting}" VerticalAlignment="Center"/>
</Page>

Ecco cosa succede in questo esempio. In <Page.Resources>, si dichiara <ResourceDictionary>. Il framework XAML crea implicitamente un dizionario di risorse quando aggiungi risorse a <Page.Resources>; tuttavia, in questo caso, non vuoi un dizionario di risorse qualsiasi, ma uno che contenga dizionari uniti.

Quindi dichiari <ResourceDictionary>, poi aggiungi cose alla sua collezione <ResourceDictionary.MergedDictionaries>. Ciascuna di queste voci assume la forma <ResourceDictionary Source="Dictionary1.xaml"/>. Per aggiungere più di un dizionario, basta aggiungere una voce di <ResourceDictionary Source="Dictionary2.xaml"/> dopo la prima voce.

Dopo <ResourceDictionary.MergedDictionaries>…</ResourceDictionary.MergedDictionaries>, puoi inserire altre risorse nel tuo dizionario principale. Puoi utilizzare le risorse di un dizionario unito come quelle di un normale dizionario. Nell'esempio precedente, {StaticResource brush} trova la risorsa nel dizionario figlio/fuso (Dictionary1.xaml), mentre {StaticResource greeting} trova la risorsa nel dizionario della pagina principale.

Nella sequenza di ricerca delle risorse, un dizionario MergedDictionaries viene controllato solo dopo aver controllato tutte le altre risorse con chiave di ResourceDictionary. Dopo aver cercato a quel livello, la ricerca raggiunge i dizionari uniti e ogni voce di MergedDictionaries viene controllata. Se esistono più dizionari uniti, questi dizionari vengono controllati nell'ordine inverso a quello in cui sono stati dichiarati nella proprietà MergedDictionaries. Nell'esempio seguente, se sia Dictionary2.xaml che Dictionary1.xaml dichiarano la stessa chiave, la chiave di Dictionary2.xaml viene utilizzata per prima perché è l'ultima nel set MergedDictionaries.

<Page
    x:Class="MSDNSample.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
    <Page.Resources>
        <ResourceDictionary>
            <ResourceDictionary.MergedDictionaries>
                <ResourceDictionary Source="Dictionary1.xaml"/>
                <ResourceDictionary Source="Dictionary2.xaml"/>
            </ResourceDictionary.MergedDictionaries>
        </ResourceDictionary>
    </Page.Resources>

    <TextBlock Foreground="{StaticResource brush}" Text="greetings!" VerticalAlignment="Center"/>
</Page>

Nell'ambito di un qualsiasi ResourceDictionary, il dizionario viene controllato per verificare l'unicità delle chiavi. Tuttavia, questo ambito non si estende alle diverse voci dei diversi file MergedDictionaries.

Puoi utilizzare la combinazione della sequenza di ricerca e la mancanza di applicazione di chiavi univoche negli ambiti dei dizionari unificati per creare una sequenza di valori di ripiego delle risorse di ResourceDictionary. Ad esempio, potresti memorizzare le preferenze dell'utente per un particolare colore del pennello nell'ultimo dizionario di risorse unito della sequenza, utilizzando un dizionario di risorse che si sincronizza con lo stato della tua applicazione e con i dati delle preferenze dell'utente. Se, tuttavia, non esistono ancora preferenze utente, puoi definire quella stessa stringa chiave per una risorsa ResourceDictionary nel file MergedDictionaries iniziale perché funga da valore di fallback. Ricorda che qualsiasi valore fornito in un dizionario di risorse primarie viene sempre controllato prima che vengano controllati i dizionari uniti, quindi se vuoi usare la tecnica di ripiego, non definire quella risorsa in un dizionario di risorse primarie.

Risorse tematiche e dizionari tematici

Una ThemeResource è simile a una StaticResource, ma la ricerca della risorsa viene rivalutata quando il tema cambia.

In questo esempio, si imposta il primo piano di un TextBlock con un valore del tema corrente.

<TextBlock Text="hello world" Foreground="{ThemeResource FocusVisualWhiteStrokeThemeBrush}" VerticalAlignment="Center"/>

Un dizionario tematico è un tipo speciale di dizionario unito che contiene le risorse che variano in base al tema che l'utente sta utilizzando sul suo dispositivo. Ad esempio, il tema "chiaro" potrebbe utilizzare un pennello di colore bianco mentre il tema "scuro" potrebbe utilizzare un pennello di colore scuro. Il pennello cambia la risorsa a cui si risolve, ma per il resto la composizione di un controllo che utilizza il pennello come risorsa potrebbe essere la stessa. Per riprodurre il comportamento di commutazione dei temi nei tuoi modelli e stili, invece di usare MergedDictionaries come proprietà per unire gli elementi nei dizionari principali, usa la proprietà ThemeDictionaries.

Ogni elemento ResourceDictionary in ThemeDictionaries deve includere un valore x:Key, Il valore è una stringa che dà il nome al tema in questione, ad esempio "Default", "Dark", "Light" o "HighContrast". In genere, Dictionary1 e Dictionary2 definiscono risorse che hanno lo stesso nome ma valori diversi.

In questo caso, si utilizza il testo rosso per il tema chiaro e il testo blu per il tema scuro.

<!-- Dictionary1.xaml -->
<ResourceDictionary
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:MSDNSample">

    <SolidColorBrush x:Key="brush" Color="Red"/>

</ResourceDictionary>

<!-- Dictionary2.xaml -->
<ResourceDictionary
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:MSDNSample">

    <SolidColorBrush x:Key="brush" Color="blue"/>

</ResourceDictionary>

In questo esempio, si imposta il primo piano di un TextBlock con un valore del tema corrente.

<Page
    x:Class="MSDNSample.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
    <Page.Resources>
        <ResourceDictionary>
            <ResourceDictionary.ThemeDictionaries>
                <ResourceDictionary Source="Dictionary1.xaml" x:Key="Light"/>
                <ResourceDictionary Source="Dictionary2.xaml" x:Key="Dark"/>
            </ResourceDictionary.ThemeDictionaries>
        </ResourceDictionary>
    </Page.Resources>
    <TextBlock Foreground="{StaticResource brush}" Text="hello world" VerticalAlignment="Center"/>
</Page>

Per i dizionari tematici, il dizionario attivo da utilizzare per la ricerca delle risorse cambia dinamicamente, ogni volta che ThemeResource markup extension viene utilizzato per fare riferimento e il sistema rileva un cambiamento di tema. Il comportamento di ricerca che viene effettuato dal sistema si basa sulla mappatura del tema attivo sul sito x:Key di un dizionario tematico specifico.

Può essere utile esaminare il modo in cui i dizionari dei temi sono strutturati nelle risorse di progettazione XAML predefinite, che sono parallele ai modelli che il Runtime di Windows utilizza di default per i suoi controlli. Apri i file XAML in \(Program Files)\Windows Kits\10\DesignTime\CommonConfiguration\Neutral\UAP\<SDK version>\Generic utilizzando un editor di testo o il tuo IDE. Nota che i dizionari dei temi sono definiti per primi in generic.xaml e che ogni dizionario dei temi definisce le stesse chiavi. Ciascuna di queste chiavi viene poi referenziata da elementi di composizione nei vari elementi con chiave che si trovano al di fuori dei dizionari dei temi e che vengono definiti successivamente nello XAML. Esiste anche un file separato themeresources.xaml per la progettazione che contiene solo le risorse del tema e i modelli extra, non i modelli di controllo predefiniti. Le aree tematiche sono dei duplicati di quelle che vedresti in generic.xaml.

Quando usi gli strumenti di progettazione XAML per modificare copie di stili e modelli, gli strumenti di progettazione estraggono sezioni dai dizionari delle risorse di progettazione XAML e le inseriscono come copie locali degli elementi del dizionario XAML che fanno parte della tua applicazione e del tuo progetto.

Per maggiori informazioni e per un elenco delle risorse specifiche del tema e di sistema disponibili per la tua applicazione, vedi Risorse del tema XAML.

Comportamento di ricerca per i riferimenti alle risorse XAML

Comportamento di ricerca è il termine che descrive il modo in cui il sistema delle risorse XAML cerca di trovare una risorsa XAML. La ricerca avviene quando una chiave viene citata come riferimento a una risorsa XAML da qualche parte nell'XAML dell'applicazione. Innanzitutto, il sistema delle risorse ha un comportamento prevedibile per quanto riguarda la verifica dell'esistenza di una risorsa in base all'ambito. Se una risorsa non viene trovata nell'ambito iniziale, l'ambito si espande. Il comportamento di ricerca continua in tutte le posizioni e gli ambiti in cui una risorsa XAML può essere definita da un'applicazione o dal sistema. Se tutti i tentativi di ricerca delle risorse falliscono, spesso si verifica un errore. Di solito è possibile eliminare questi errori durante il processo di sviluppo.

Il comportamento di ricerca per i riferimenti alle risorse XAML parte dall'oggetto in cui viene applicato l'utilizzo effettivo e dalla sua proprietà Resources. Se in questa posizione esiste un oggetto ResourceDictionary, viene eseguita una ricerca in ResourceDictionary per individuare l'elemento con la chiave richiesta. Questo primo livello di ricerca è raramente rilevante perché di solito non si definisce e poi si fa riferimento a una risorsa sullo stesso oggetto. In effetti, una proprietà Resources spesso non esiste. Puoi fare riferimenti a risorse XAML praticamente da qualsiasi punto di XAML; non sei limitato alle proprietà delle sottoclassi di FrameworkElement.

La sequenza di ricerca controlla quindi l'oggetto genitore successivo nell'albero degli oggetti di runtime dell'applicazione. Se esiste un FrameworkElement.Resources e contiene un ResourceDictionary, viene richiesto l'elemento del dizionario con la stringa chiave specificata. Se la risorsa viene trovata, la sequenza di ricerca si interrompe e l'oggetto viene fornito alla posizione in cui è stato fatto il riferimento. Altrimenti, il comportamento di ricerca avanza al livello genitore successivo verso la radice dell'albero degli oggetti. La ricerca continua ricorsivamente verso l'alto fino a raggiungere l'elemento radice dello XAML, esaurendo la ricerca di tutte le possibili posizioni immediate delle risorse.

Nota

È una pratica comune definire tutte le risorse immediate al livello principale di una pagina, sia per sfruttare questo comportamento di ricerca delle risorse, sia come convenzione dello stile di markup XAML.

Se la risorsa richiesta non viene trovata tra le risorse immediate, il passo successivo consiste nel controllare la proprietà Application.Resources. Application.Resources è il posto migliore per inserire tutte le risorse specifiche dell'applicazione che sono referenziate da più pagine nella struttura di navigazione della tua applicazione.

Importante

L'ordine delle risorse aggiunte a un oggetto ResourceDictionary influisce sull'ordine in cui vengono applicate. Il dizionario XamlControlsResources esegue l'override di molte chiavi di risorsa predefinite e pertanto deve essere aggiunto a Application.Resources per primo, in modo che non esegua l'override di altri stili o risorse personalizzate nell'app.

I modelli di controllo hanno un'altra possibile collocazione nella ricerca dei riferimenti: i dizionari dei temi. Un dizionario tematico è un singolo file XAML che ha come radice un elemento ResourceDictionary. Il dizionario tematico potrebbe essere un dizionario unito da Application.Resources. Il dizionario dei temi potrebbe anche essere il dizionario dei temi specifici del controllo per un modello di controllo personalizzato.

Infine, c'è una ricerca di risorse che si basa sulle risorse della piattaforma. Le risorse della piattaforma includono i modelli di controllo definiti per ciascuno dei temi dell'interfaccia utente del sistema e che definiscono l'aspetto predefinito di tutti i controlli utilizzati per l'interfaccia utente in un'applicazione Windows Runtime. Le risorse della piattaforma includono anche una serie di risorse denominate che riguardano l'aspetto e i temi dell'intero sistema. Queste risorse sono tecnicamente un elemento di MergedDictionaries e quindi sono disponibili per la ricerca da XAML o dal codice una volta che l'applicazione è stata caricata. Ad esempio, le risorse del tema di sistema includono una risorsa chiamata "SystemColorWindowTextColor" che fornisce una definizione di Color per far corrispondere il colore del testo dell'applicazione al colore del testo di una finestra di sistema che deriva dal sistema operativo e dalle preferenze dell'utente. Altri stili XAML della tua applicazione possono fare riferimento a questo stile, oppure il tuo codice può ottenere un valore di ricerca della risorsa (e lanciarlo in Color nel caso di esempio).

Per altre informazioni e per un elenco delle risorse specifiche dei temi e di sistema disponibili per un'app di Windows che usa XAML, vedi Risorse del tema XAML.

Se la chiave richiesta non viene trovata in nessuna di queste posizioni, si verifica un errore/eccezione di parsing XAML. In alcune circostanze, l'eccezione di parsing XAML può essere un'eccezione run-time che non viene rilevata né da un'azione di compilazione del markup XAML, né da un ambiente di progettazione XAML.

A causa del comportamento di ricerca a livelli per i dizionari di risorse, puoi definire deliberatamente più elementi di risorse che hanno lo stesso valore di stringa come chiave, a patto che ogni risorsa sia definita a un livello diverso. In altre parole, sebbene le chiavi debbano essere uniche all'interno di un determinato ResourceDictionary, il requisito di unicità non si estende alla sequenza di comportamenti di ricerca nel suo complesso. Durante la ricerca, solo il primo oggetto di questo tipo che viene recuperato con successo viene utilizzato per il riferimento alla risorsa XAML e poi la ricerca si interrompe. Potresti utilizzare questo comportamento per richiedere la stessa risorsa XAML tramite una chiave in varie posizioni all'interno dell'XAML della tua applicazione, ma ottenere risorse diverse, a seconda dell'ambito da cui è stato fatto il riferimento alla risorsa XAML e di come si comporta quel particolare lookup.

Riferimenti in avanti all'interno di un ResourceDictionary

I riferimenti alle risorse XAML all'interno di un particolare dizionario di risorse devono fare riferimento a una risorsa già definita con una chiave e tale risorsa deve comparire lessicalmente prima del riferimento alla risorsa. I riferimenti in avanti non possono essere risolti da un riferimento a una risorsa XAML. Per questo motivo, se utilizzi i riferimenti alle risorse XAML all'interno di un'altra risorsa, devi progettare la struttura del tuo dizionario delle risorse in modo che le risorse utilizzate da altre risorse siano definite prima in un dizionario delle risorse.

Le risorse definite a livello di app non possono fare riferimento a risorse immediate. Questo equivale a tentare un riferimento in avanti, perché le risorse dell'app vengono effettivamente elaborate per prime (all'avvio dell'app e prima che venga caricato il contenuto della pagina di navigazione). Tuttavia, qualsiasi risorsa immediata può fare riferimento a una risorsa dell'app e questa può essere una tecnica utile per evitare situazioni di riferimento in avanti.

Le risorse XAML devono essere condivisibili

La condizione per l'esistenza di un oggetto in un ResourceDictionary è che l'oggetto sia condivisibile.

La condivisibilità è necessaria perché, quando l'albero degli oggetti di un'applicazione viene costruito e utilizzato in fase di esecuzione, gli oggetti non possono esistere in più posizioni dell'albero. Internamente, il sistema delle risorse crea copie dei valori delle risorse da utilizzare nel grafico degli oggetti della tua applicazione quando viene richiesta una risorsa XAML.

Un ResourceDictionary e Windows Runtime XAML in generale supportano questi oggetti per un utilizzo condivisibile:

Puoi anche utilizzare i tipi personalizzati come risorse condivisibili se segui i modelli di implementazione necessari. Definisci queste classi nel tuo codice di supporto (o nei componenti di runtime che includi) e poi istanzia queste classi in XAML come risorsa. Esempi sono le sorgenti di dati a oggetti e le implementazioni di IValueConverter per il binding dei dati.

I tipi personalizzati devono avere un costruttore predefinito, perché è quello che il parser XAML utilizza per istanziare una classe. I tipi personalizzati usati come risorse non possono avere la classe UIElement nella propria ereditarietà, perché un UIElement non può essere mai condivisibile (è sempre destinato a rappresentare esattamente un elemento dell'interfaccia utente presente in una posizione dell'oggetto grafico dell'app di runtime).

Ambito di utilizzo di UserControl

Un elemento UserControl presenta una situazione particolare per quanto riguarda il comportamento di ricerca delle risorse, perché ha i concetti intrinseci di ambito di definizione e ambito di utilizzo. Un UserControl che fa riferimento a una risorsa XAML dal suo ambito di definizione deve essere in grado di supportare la ricerca di tale risorsa all'interno della propria sequenza di ricerca dell'ambito di definizione, ovvero non può accedere alle risorse dell'app. Da un ambito di utilizzo di UserControl, un riferimento a una risorsa viene trattato come se si trovasse all'interno della sequenza di ricerca verso la radice della sua pagina di utilizzo (proprio come qualsiasi altro riferimento a una risorsa fatto da un oggetto in un albero di oggetti caricato) e può accedere alle risorse dell'applicazione.

Dizionario di risorse e XamlReader.Load

Puoi utilizzare un ResourceDictionary come radice o come parte dell'input XAML per il metodo XamlReader.Load. Puoi anche includere i riferimenti alle risorse XAML in quello XAML se tutti questi riferimenti sono completamente autosufficienti nello XAML inviato per il caricamento. XamlReader.Load analizza il codice XAML in un contesto che non riconosce altri oggetti ResourceDictionary, nemmeno Application.Resources. Inoltre, non utilizzare {ThemeResource} dall'interno dello XAML inviato a XamlReader.Load.

Utilizzare un ResourceDictionary dal codice

La maggior parte degli scenari per un ResourceDictionary sono gestiti esclusivamente in XAML. Dichiara il contenitore ResourceDictionary e le risorse al suo interno come un file XAML o un insieme di nodi XAML in un file di definizione dell'interfaccia utente. E poi si utilizzano i riferimenti alle risorse XAML per richiedere tali risorse da altre parti di XAML. Tuttavia, ci sono alcuni scenari in cui la tua applicazione potrebbe voler modificare il contenuto di un ResourceDictionary utilizzando del codice che viene eseguito mentre l'applicazione è in esecuzione, o almeno interrogare il contenuto di un ResourceDictionary per vedere se una risorsa è già definita. Queste chiamate del codice vengono effettuate su un'istanza ResourceDictionary, quindi devi prima recuperarne una: un oggetto ResourceDictionary immediato da qualche parte nell'albero di oggetti recuperando la proprietà FrameworkElement.Resources oppure Application.Current.Resources.

Nel codice C# o Microsoft Visual Basic, puoi fare riferimento a una risorsa in un determinato ResourceDictionary utilizzando l'indicizzatore (Item). Un ResourceDictionary è un dizionario con chiave a stringa, quindi l'indicizzatore utilizza la chiave a stringa invece di un indice intero. Nel codice delle estensioni dei componenti di Visual C++ (C++/CX), usa Lookup.

Quando si utilizza il codice per esaminare o modificare un ResourceDictionary, il comportamento delle API come Lookup o Item non passa dalle risorse immediate alle risorse dell'applicazione; questo è un comportamento del parser XAML che avviene solo durante il caricamento delle pagine XAML. In fase di esecuzione, l'ambito delle chiavi è limitato all'istanza di ResourceDictionary che si sta utilizzando in quel momento. Tuttavia, questo ambito si estende a MergedDictionaries.

Se richiedi una chiave che non esiste in ResourceDictionary, è possibile che non venga visualizzato un errore ma che il valore restituito sia semplicemente null. Tuttavia, potresti ricevere un errore se cerchi di utilizzare il valore restituito null come valore. L'errore verrebbe dal setter della proprietà, non dalla chiamata a ResourceDictionary. L'unico modo per evitare un errore è che la proprietà accetti null come valore valido. Si noti come questo comportamento contrasta con il comportamento di ricerca XAML al momento del parse di XAML; la mancata risoluzione della chiave fornita da XAML al momento del parse comporta un errore di parse XAML, anche nei casi in cui la proprietà avrebbe potuto accettare null.

I dizionari di risorse uniti sono inclusi nell'ambito dell'indice del dizionario di risorse primario che fa riferimento al dizionario unito in fase di esecuzione. In altre parole, puoi usare l'elemento Item o il metodo Lookup del dizionario principale per trovare gli oggetti effettivamente definiti nel dizionario unito. In questo caso, il comportamento della ricerca assomiglia a quello del parse-time XAML: se ci sono più oggetti nei dizionari uniti che hanno la stessa chiave, viene restituito l'oggetto del dizionario aggiunto per ultimo.

Puoi aggiungere elementi a un ResourceDictionary esistente chiamando Add (C# o Visual Basic) or Insert (C++/CX). Puoi aggiungere gli elementi alle risorse immediate o alle risorse dell'applicazione. Entrambe le chiamate API richiedono una chiave, che soddisfa il requisito per cui ogni elemento di un ResourceDictionary deve avere una chiave. Tuttavia, gli elementi che aggiungi a un ResourceDictionary ResourceDictionary in fase di esecuzione non sono rilevanti per i riferimenti alle risorse XAML. La ricerca dei riferimenti alle risorse XAML avviene quando lo XAML viene analizzato per la prima volta durante il caricamento dell'applicazione (o quando viene rilevata una modifica del tema). Le risorse aggiunte alle raccolte in fase di esecuzione non erano disponibili allora e la modifica del ResourceDictionary non invalida una risorsa già recuperata dallo stesso, anche se si modifica il valore di tale risorsa.

Puoi anche rimuovere gli elementi da un ResourceDictionary in fase di esecuzione, fare copie di alcuni o di tutti gli elementi o altre operazioni. L'elenco dei membri di ResourceDictionary indica quali API sono disponibili. Nota che, poiché ResourceDictionary dispone di un'API proiettata per supportare le interfacce di raccolta sottostanti, le opzioni relative alle API varieranno in base al linguaggio che usi, ad esempio C# o Visual Basic piuttosto che C++/CX.

Dizionario delle risorse e localizzazione

Un ResourceDictionary XAML potrebbe contenere inizialmente delle stringhe che devono essere localizzate. In tal caso, memorizza queste stringhe come risorse del progetto invece che in un ResourceDictionary. Elimina le stringhe dallo XAML e assegna invece all'elemento proprietario un valore x:Uid directive. Quindi, definisci una risorsa in un file di risorse. Fornisci un nome di risorsa nella forma XUIDValue.PropertyName e un valore di risorsa della stringa che deve essere localizzata.

Ricerca risorse personalizzata

Per gli scenari avanzati, puoi implementare una classe che può avere un comportamento diverso dal comportamento di ricerca dei riferimenti alle risorse XAML descritto in questo argomento. A tale scopo devi implementare la classe CustomXamlResourceLoader, quindi puoi accedere a tale comportamento usando l'estensione di markup CustomResource per i riferimenti alle risorse, anziché usare StaticResource o ThemeResource. La maggior parte delle applicazioni non prevede scenari che lo richiedano. Per maggiori informazioni, vedi CustomXamlResourceLoader.