Condividi tramite


Riferimenti alle risorse ResourceDictionary e XAML

Puoi definire l'interfaccia utente o le risorse per la tua app usando XAML. Le risorse sono in genere definizioni di alcuni oggetti che si prevede di usare più volte. Per fare riferimento a una risorsa XAML in un secondo momento, specificare una chiave che funzioni come se fosse il nome della risorsa. Puoi fare riferimento a una risorsa in un'app o da qualsiasi pagina XAML al suo interno. Puoi definire le risorse usando un elemento ResourceDictionary dallo XAML di Windows Runtime. Puoi quindi fare riferimento alle risorse usando un'estensione di markup StaticResource o l'estensione di markup ThemeResource.

Gli elementi XAML che potresti voler dichiarare più spesso nelle risorse XAML includono Style, ControlTemplate, i componenti di animazione e le sottoclassi di Brush. In questo articolo viene illustrato come definire un ResourceDictionary e risorse chiave, e come le risorse XAML siano correlate ad altre risorse definite come parte del pacchetto dell'app o dell'applicazione. Spieghiamo anche le funzionalità avanzate del dizionario delle risorse, come ad esempio MergedDictionaries e ThemeDictionaries.

Prerequisiti

Conoscenza approfondita del markup XAML. È consigliabile leggere panoramica di XAML.

Definire e usare le risorse XAML

Le risorse XAML sono oggetti a cui viene fatto riferimento più volte dal markup. Le risorse vengono definite in un ResourceDictionary, in genere in un file separato o nella parte superiore della pagina di markup, come illustrato di seguito.

<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 delle risorse.
  • <x:String>: definisce la risorsa con la chiave "greeting".
  • {StaticResource greeting} : cerca la risorsa con la chiave "greeting", assegnata alla proprietà Text del TextBlock.

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

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

In questo caso, sia un pennello che una stringa vengono dichiarati come risorse e usati dai controlli in 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. In genere la chiave è una stringa definita con x:Key="myString". Esistono tuttavia alcuni altri modi per specificare una chiave:

  • Style e ControlTemplate richiedono un TargetTypee useranno il TargetType come chiave se non viene specificato x:Key. In questo caso, la chiave è l'oggetto Type effettivo, non una stringa. (Vedere gli esempi seguenti)
  • risorse DataTemplate con un TargetType useranno l' TargetType come chiave se non viene specificato x:Key. In questo caso, la chiave è l'oggetto Type effettivo, non una stringa.
  • x:Name può essere usato invece di x:Key. Tuttavia, x:Name genera anche un campo del codice sottostante per la risorsa. Di conseguenza, x:Name è meno efficiente di x:Key perché tale campo deve essere inizializzato quando viene caricata la pagina.

L'estensione di markup StaticResource può recuperare le risorse solo con un nome stringa (x:Key o x:Name). Tuttavia, il framework XAML cerca anche risorse di stile implicite (quelle che usano TargetType anziché x:Key o x:Name) quando decide quale stile e modello usare per un controllo che non ha impostato le proprietà Style e ContentTemplate o ItemTemplate .

In questo caso, l' style ha una chiave implicita di typeof(Button)e poiché la Button nella parte inferiore della pagina non specifica una proprietà Style , cerca uno stile con chiave di 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 altre info sugli stili impliciti e sul loro funzionamento, vedi Stili dei controlli e modelli di controllo .

Cercare le risorse nel codice

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

Avvertimento

Quando si esegue una ricerca di risorse nel codice, vengono esaminate solo le risorse nel dizionario Page.Resources. A differenza dell'estensione di markup StaticResource , il codice non esegue il fallback al dizionario Application.Resources qualora le risorse non vengano trovate nel primo dizionario.

 

Questo esempio mostra come recuperare la risorsa redButtonStyle dal dizionario 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 a livello di app dal codice, usare Application.Current.Resources per ottenere il dizionario risorse dell'app, come illustrato di seguito.

<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>();
    }

È anche possibile aggiungere una risorsa dell'applicazione nel codice.

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

  • In primo luogo, è necessario aggiungere le risorse prima che qualsiasi pagina tenti di usare la risorsa.
  • In secondo luogo, non è possibile aggiungere risorse nel costruttore dell'app.

È possibile evitare entrambi i problemi se si aggiunge 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 oggetto ResourceDictionary

FrameworkElement è una classe base da cui ereditano i controlli e dispone di una proprietà Resources. È quindi possibile aggiungere un dizionario risorse locale a qualsiasi FrameworkElement.

In questo caso, sia la Pagina che il Bordo dispongono di dizionari risorse e hanno entrambi una risorsa denominata "greeting". Il TextBlock denominato "textBlock2" si trova all'interno del Border, quindi la ricerca delle risorse si effettua prima sulle risorse del Border, poi sulle risorse del Pagee infine sulle risorse dell'Application. Il TextBlock leggerà "Hola mundo".

Per accedere alle risorse dell'elemento dal codice, usare la proprietà Resources dell'elemento. L'accesso alle risorse di un FrameworkElementnel codice, invece che tramite XAML, cercherà solo in quel dizionario, non nei dizionari degli elementi padre.

<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 combinati

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

Suggerimento È possibile creare un file di Dizionario Risorse in Microsoft Visual Studio usando l'opzione Aggiungi > Nuovo elemento… > Dizionario Risorse dal menu Progetto.

Qui definisci un dizionario risorse in un file XAML separato denominato 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 usare quel 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 accade in questo esempio. In <Page.Resources>dichiari <ResourceDictionary>. Il framework XAML crea in modo implicito un dizionario delle risorse quando si aggiungono risorse a <Page.Resources>; tuttavia, in questo caso, non si desidera un dizionario delle risorse qualsiasi, ma piuttosto uno che contenga dizionari incorporati.

Quindi dichiari <ResourceDictionary>, poi aggiungi elementi alla relativa raccolta di <ResourceDictionary.MergedDictionaries>. Ognuna di queste voci assume il formato <ResourceDictionary Source="Dictionary1.xaml"/>. Per aggiungere più dizionari, è sufficiente aggiungere una voce <ResourceDictionary Source="Dictionary2.xaml"/> dopo la prima voce.

Dopo <ResourceDictionary.MergedDictionaries>…</ResourceDictionary.MergedDictionaries>, è possibile inserire facoltativamente risorse aggiuntive nel dizionario principale. Le risorse di un dizionario unito vengono usate esattamente come un dizionario normale. Nell'esempio precedente, {StaticResource brush} trova la risorsa nel dizionario figlio o unito (Dictionary1.xaml), mentre {StaticResource greeting} trova la risorsa nel dizionario della pagina principale.

Nella sequenza di ricerca delle risorse, viene controllato un dizionario MergedDictionaries solo dopo il controllo di tutte le altre risorse con chiave nel ResourceDictionarystesso. Dopo aver cercato in quel livello, la ricerca raggiunge i dizionari uniti e ogni elemento in MergedDictionaries viene controllato. Se esistono più dizionari uniti, questi dizionari vengono controllati nell'inverso dell'ordine in cui vengono dichiarati nella proprietà MergedDictionaries. Nell'esempio seguente, se sia Dictionary2.xaml che Dictionary1.xaml hanno dichiarato la stessa chiave, la chiave di Dictionary2.xaml viene usata per prima perché è l'ultima nel MergedDictionaries impostato.

<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 qualsiasi ResourceDictionary, il dizionario viene controllato per verificare l'univocità della chiave. Tuttavia, tale ambito non si estende tra elementi diversi in diversi MergedDictionaries file.

È possibile usare la combinazione della sequenza di ricerca e la mancanza di imposizione di chiavi univoche negli ambiti del dizionario unito per creare una sequenza di valori di fallback di risorse ResourceDictionary. Ad esempio, è possibile archiviare le preferenze utente per un determinato colore del pennello nell'ultimo dizionario risorse unito nella sequenza, usando un dizionario risorse che si sincronizza con i dati relativi allo stato e alle preferenze utente dell'app. Tuttavia, se non esistono ancora preferenze utente, è possibile definire la stessa stringa di chiave per una risorsa ResourceDictionary nel file iniziale MergedDictionaries, e può fungere da valore di fallback. Tenere presente che qualsiasi valore specificato in un dizionario risorse primario viene sempre controllato prima che vengano controllati i dizionari uniti, quindi se si vuole usare la tecnica di fallback, non definire tale risorsa in un dizionario risorse primario.

Risorse del tema e dizionari dei temi

Un ThemeResource è simile a un StaticResource, ma la ricerca delle risorse viene rivalutata quando il tema cambia.

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

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

Un dizionario dei temi è un tipo speciale di dizionario unito che contiene le risorse che variano con il tema che un utente usa attualmente nel dispositivo. Ad esempio, il tema "chiaro" potrebbe usare un pennello colore bianco, mentre il tema "scuro" potrebbe usare un pennello colore scuro. Il pennello modifica la risorsa a cui si riferisce, ma la composizione di un controllo che utilizza il pennello come risorsa potrebbe comunque rimanere invariata. Per riprodurre il comportamento del cambio di tema nei modelli e negli stili personalizzati, invece di usare MergedDictionaries come proprietà per unire gli elementi nei dizionari principali, utilizzare la proprietà ThemeDictionaries.

Ogni elemento ResourceDictionary all'interno di ThemeDictionaries deve avere un valore di x:Key. Il valore è una stringa che assegna un nome al tema pertinente, ad esempio "Default", "Dark", "Light" o "HighContrast". In genere, Dictionary1 e Dictionary2 definiranno le risorse con gli stessi nomi ma valori diversi.

Qui si usa 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 su 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 dei temi, il dizionario attivo da usare per la ricerca delle risorse cambia in modo dinamico, ogni volta che l'estensione di markup ThemeResource viene usata per creare il riferimento e il sistema rileva una modifica del tema. Il comportamento di ricerca eseguito dal sistema è basato sull'associazione del tema attivo al 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 parallelizzano i modelli usati da Windows Runtime per impostazione predefinita per i relativi controlli. Apri i file XAML in \(Programmi)\Windows Kits\10\DesignTime\CommonConfiguration\Neutral\UAP\<versione SDK>\Generic usando un editor di testo o il tuo IDE. Si noti che i dizionari dei temi vengono definiti per primi in generic.xaml e come ogni dizionario dei temi definisce le stesse chiavi. A ogni chiave viene quindi fatto riferimento da elementi di composizione nei vari elementi con chiave esterni ai dizionari dei temi e definiti più avanti in XAML. Esiste anche un file themeresources.xaml separato per la progettazione che contiene solo le risorse del tema e i modelli aggiuntivi, non i modelli di controllo predefiniti. Le aree dei temi sono duplicati di ciò che vedresti in generic.xaml.

Quando usi strumenti di progettazione XAML per modificare copie di stili e modelli, gli strumenti di progettazione estraggono sezioni dai dizionari risorse di progettazione XAML e li inseriscono come copie locali degli elementi del dizionario XAML che fanno parte dell'app e del progetto.

Per altre info e per un elenco delle risorse specifiche del tema e di sistema disponibili per la tua app, vedi risorse del tema XAML.

Comportamento di ricerca per i riferimenti alle risorse XAML

comportamento di ricerca è il termine che descrive come il sistema di risorse XAML tenta di trovare una risorsa XAML. La ricerca si verifica quando viene fatto riferimento a una chiave come riferimento a una risorsa XAML da un punto qualsiasi nel codice XAML dell'app. In primo luogo, il sistema delle risorse ha un comportamento prevedibile per dove verificherà l'esistenza di una risorsa in base all'ambito. Se non viene trovata una risorsa nell'ambito iniziale, l'ambito si espande. Il comportamento di ricerca continua in tutte le posizioni e gli ambiti in cui una risorsa XAML potrebbe essere definita da un'app o dal sistema. Se tutti i possibili tentativi di ricerca delle risorse hanno esito negativo, viene spesso restituito un errore. In genere è possibile eliminare questi errori durante il processo di sviluppo.

Il comportamento di ricerca per i riferimenti alle risorse XAML inizia con l'oggetto in cui viene applicato l'utilizzo effettivo e la relativa proprietà Resources. Se esiste un ResourceDictionary, tale ResourceDictionary viene controllato per verificare la presenza di un elemento con la chiave richiesta. Questo primo livello di ricerca è raramente rilevante perché, di solito, non si definisce una risorsa, né vi si fa riferimento, sullo stesso oggetto. In effetti, una proprietà risorse spesso non esiste. È possibile fare riferimenti alle risorse XAML quasi ovunque; non sei limitato alle proprietà delle sottoclassi di FrameworkElement.

La sequenza di ricerca controlla quindi il successivo oggetto padre nell'albero degli oggetti a runtime dell'app. Se esiste un FrameworkElement.Resources e contiene un ResourceDictionary, viene richiesto l'elemento del dizionario con la stringa di chiave specificata. Se la risorsa viene trovata, la sequenza di ricerca si arresta e l'oggetto viene fornito alla posizione in cui è stato effettuato il riferimento. In caso contrario, il comportamento di ricerca passa al livello padre successivo verso la radice dell'albero degli oggetti. La ricerca continua in modo ricorsivo verso l'alto fino a quando non viene raggiunto l'elemento radice del codice XAML, esaurendo la ricerca di tutte le possibili posizioni immediate delle risorse.

Annotazioni

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

Se la risorsa richiesta non viene trovata nelle risorse immediate, il passaggio di ricerca successivo consiste nel controllare la proprietà Application.Resources. Application.Resources è la posizione migliore per inserire le risorse specifiche dell'app a cui fanno riferimento diverse pagine nella struttura di navigazione dell'app.

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 dovrebbe quindi essere aggiunto a Application.Resources per primo, in modo che non esegua l'override di altri stili o risorse personalizzati nell'app.

I modelli di controllo hanno un'altra possibile posizione nella consultazione dei riferimenti: dizionari dei temi. Un dizionario dei temi è un singolo file XAML che ha come radice un elemento ResourceDictionary. Il dizionario dei temi potrebbe essere un dizionario integrato da Application.Resources. Il dizionario dei temi potrebbe anche essere il dizionario dei temi specifico del controllo per un controllo personalizzato basato su modelli.

Infine, è disponibile una ricerca delle risorse rispetto alle risorse della piattaforma. Le risorse della piattaforma includono i modelli di controllo definiti per ognuno dei temi dell'interfaccia utente di sistema e che definiscono l'aspetto predefinito di tutti i controlli usati per l'interfaccia utente in un'app di Windows Runtime. Le risorse della piattaforma includono anche un set di risorse denominate correlate all'aspetto e ai temi a livello di sistema. Queste risorse sono tecnicamente un elemento MergedDictionaries e quindi sono disponibili per essere richiamate da XAML o codice una volta che l'app è stata caricata. Ad esempio, le risorse del tema di sistema includono una risorsa denominata "SystemColorWindowTextColor" che fornisce una definizione di Color per associare il colore del testo dell'app al colore del testo di una finestra di sistema proveniente dal sistema operativo e dalle preferenze utente. Altri stili XAML nella tua app possono fare riferimento a questo stile, oppure il codice può ottenere un valore di riferimento della risorsa (ed eseguirne il cast a Color nel caso di esempio).

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

Se la chiave richiesta non viene ancora trovata in nessuna di queste posizioni, si verifica un errore o un'eccezione di analisi XAML. In determinate circostanze, l'eccezione di analisi XAML può essere un'eccezione di runtime non rilevata da un'azione di compilazione del markup XAML o da un ambiente di progettazione XAML.

A causa del comportamento di ricerca a livelli per i dizionari risorse, è possibile definire deliberatamente più elementi di risorsa con lo stesso valore stringa della chiave, purché ogni risorsa sia definita a un livello diverso. In altre parole, anche se le chiavi devono essere univoche all'interno di qualsiasi ResourceDictionary, il requisito di univocità non si estende alla sequenza di comportamento di ricerca nel suo complesso. Durante la ricerca, solo il primo oggetto recuperato correttamente viene usato per il riferimento alla risorsa XAML e quindi la ricerca si arresta. Puoi usare questo comportamento per richiedere la stessa risorsa XAML per chiave in varie posizioni all'interno del codice XAML dell'app, ma recuperare risorse diverse, a seconda dell'ambito da cui è stato fatto il riferimento alla risorsa XAML e del comportamento di tale particolare ricerca.

Riferimenti anticipati all'interno di un ResourceDictionary

I riferimenti alle risorse XAML all'interno di un particolare dizionario risorse devono fare riferimento a una risorsa già definita con una chiave e tale risorsa deve essere visualizzata in modo lessicale prima del riferimento alla risorsa. I riferimenti in avanti non possono essere risolti da un riferimento a una risorsa XAML. Per questo motivo, se usi riferimenti alle risorse XAML dall'interno di un'altra risorsa, devi progettare la struttura del dizionario risorse in modo che le risorse usate da altre risorse vengano definite per prime in un dizionario risorse.

Le risorse definite a livello di app non possono fare riferimento alle risorse immediate. È come tentare di fare un riferimento anticipato, perché le risorse dell'app vengono effettivamente elaborate per prime (all'avvio dell'app e prima del caricamento di qualsiasi contenuto della pagina di navigazione). Tuttavia, qualsiasi risorsa immediata può fare riferimento a una risorsa dell'app e può essere una tecnica utile per evitare situazioni di riferimento inoltrato.

Le risorse XAML devono essere condivisibili

Affinché un oggetto esista in un ResourceDictionary, tale oggetto deve essere condivisibile.

La condivisione è necessaria perché, quando l'albero di oggetti di un'app viene costruito e usato in fase di esecuzione, gli oggetti non possono esistere in più posizioni nell'albero. Internamente, il sistema di risorse crea copie dei valori delle risorse da usare nell'oggetto grafico dell'app quando viene richiesta ogni risorsa XAML.

Un ResourceDictionary e, in generale, XAML di Windows Runtime supportano questi oggetti per un utilizzo condiviso.

È anche possibile usare tipi personalizzati come risorsa condivisibile se si seguono i modelli di implementazione necessari. Definisci tali classi nel codice di backup (o nei componenti di runtime inclusi) e quindi crea un'istanza di tali classi in XAML come risorsa. Esempi sono origini dati oggetto e implementazioni di IValueConverter per il data binding.

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

Ambito di utilizzo di UserControl

Un elemento UserControl presenta una situazione speciale per il comportamento di ricerca delle risorse perché presenta i concetti intrinseci di un ambito di definizione e un ambito di utilizzo. Un UserControl che fa riferimento a una risorsa XAML dal relativo 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. Dal punto di vista dell'uso di un UserControl, un riferimento a una risorsa è considerato all'interno della sequenza di ricerca verso la radice della pagina di utilizzo (come qualsiasi altro riferimento a una risorsa fatto da un oggetto in un albero di oggetti caricato) e può accedere alle risorse dell'applicazione.

ResourceDictionary e XamlReader.Load

Puoi utilizzare un ResourceDictionary sia come radice che come parte dell'input XAML per il metodo XamlReader.Load. Puoi anche includere riferimenti alle risorse XAML in quel codice XAML se tutti questi riferimenti sono completamente indipendenti nel codice XAML inviato per il caricamento. XamlReader.Load analizza il codice XAML in un contesto che non è a conoscenza di alcun altro oggetto ResourceDictionary, neanche di Application.Resources. Inoltre, non usare {ThemeResource} all'interno di XAML inviato a XamlReader.Load.

Uso di ResourceDictionary dal codice

La maggior parte degli scenari per un ResourceDictionary viene gestita esclusivamente in XAML. Dichiari il ResourceDictionary contenitore e le risorse all'interno come file XAML o set di nodi XAML in un file di definizione dell'interfaccia utente. Quindi si usano i riferimenti alle risorse XAML per richiedere tali risorse da altre parti di XAML. Esistono tuttavia alcuni scenari in cui l'app potrebbe voler modificare il contenuto di un ResourceDictionary usando codice eseguito durante l'esecuzione dell'app o almeno per eseguire una query sul contenuto di un ResourceDictionary per verificare se una risorsa è già definita. Queste chiamate di codice vengono effettuate in un'istanza di ResourceDictionary, quindi è necessario recuperarne una, ovvero un ResourceDictionary immediato da qualche parte nell'albero degli oggetti recuperando FrameworkElement.Resourceso Application.Current.Resources.

Nel codice C# o Microsoft Visual Basic è possibile fare riferimento a una risorsa in un determinato ResourceDictionary usando l'indicizzatore (Item). Un ResourceDictionary è un dizionario con chiave di stringa, quindi l'indicizzatore usa la chiave stringa anziché un indice integer. Nel codice delle estensioni del componente di Visual C++ (C++/CX), usa Ricerca.

Quando si usa il codice per esaminare o modificare un ResourceDictionary, il comportamento per le API come Ricerca o Elemento non passa dalle risorse immediate alle risorse dell'app; si tratta di un comportamento del parser XAML che si verifica solo quando vengono caricate le pagine XAML. In fase di esecuzione, l'ambito delle chiavi è indipendente dall'istanza ResourceDictionary usata al momento. Tuttavia, tale ambito si estende a MergedDictionaries.

Inoltre, se si richiede una chiave che non esiste nel ResourceDictionary, potrebbe non essere presente un errore; Il valore restituito può essere fornito semplicemente come null. È comunque possibile che venga visualizzato un errore se si prova a utilizzare il valore restituito null. L'errore proviene dal setter della proprietà, non dalla chiamata ResourceDictionary. L'unico modo per evitare un errore è se la proprietà accettasse null come valore valido. Tieni presente che questo comportamento contrasta con il comportamento di ricerca durante l'analisi XAML; un mancato riconoscimento della chiave fornita durante l'analisi XAML comporta un errore di analisi XAML, anche nei casi in cui la proprietà potrebbe accettare null.

I dizionari delle risorse uniti vengono inclusi nell'indice del dizionario delle risorse primario che fa riferimento al dizionario unito durante l'esecuzione. In altre parole, è possibile usare Item o Lookup del dizionario primario per trovare gli oggetti effettivamente definiti nel dizionario unito. In questo caso, il comportamento di ricerca è simile al comportamento di ricerca XAML in fase di analisi: se sono presenti più oggetti nei dizionari uniti con la stessa chiave, viene restituito l'oggetto dell'ultimo dizionario aggiunto.

È possibile aggiungere elementi a un ResourceDictionary esistente chiamando Aggiungi (C# o Visual Basic) o Inserisci (C++/CX). È possibile aggiungere gli elementi alle risorse immediate o alle risorse dell'app. Una di queste chiamate API richiede una chiave, che soddisfa il requisito che ogni elemento in un ResourceDictionary deve avere una chiave. Tuttavia, gli elementi aggiunti a un ResourceDictionary in fase di esecuzione non sono rilevanti per i riferimenti alle risorse XAML. La ricerca necessaria per i riferimenti alle risorse XAML avviene quando XAML viene inizialmente analizzato durante il caricamento dell'app (o quando viene individuata una modifica del tema). Le risorse aggiunte alle raccolte in fase di esecuzione non erano disponibili e la modifica del ResourceDictionary non invalida una risorsa già recuperata anche se si modifica il valore di tale risorsa.

È anche possibile rimuovere elementi da un ResourceDictionary in fase di esecuzione, creare copie di alcuni o tutti gli elementi o altre operazioni. L'elenco dei membri per ResourceDictionary indica quali API sono disponibili. Si noti che, poiché ResourceDictionary ha un'API proiettata per supportare le interfacce sottostanti della raccolta, le opzioni API possono variare a seconda dell'uso di C# o Visual Basic rispetto a C++/CX.

ResourceDictionary e localizzazione

Un ResourceDictionary XAML potrebbe inizialmente contenere stringhe da localizzare. In tal caso, archiviare queste stringhe come risorse di progetto anziché in un ResourceDictionary. Rimuovi le stringhe dal codice XAML e assegna un valore direttiva x:Uid all'elemento proprietario. Definire quindi una risorsa in un file di risorse. Specificare un nome di risorsa nel formato XUIDValue.PropertyName e un valore della risorsa della stringa da localizzare.

Ricerca di risorse personalizzate

Per gli scenari avanzati, puoi implementare una classe che può avere un comportamento diverso rispetto al comportamento di ricerca delle risorse XAML descritto in questo argomento. A tale scopo, si implementa la classe CustomXamlResourceLoadere quindi è possibile accedere a tale comportamento usando l'estensione di markup CustomResource per i riferimenti alle risorse, anziché usare StaticResource o ThemeResource. La maggior parte delle app non avrà scenari che richiedono questo problema. Per ulteriori informazioni, vedi CustomXamlResourceLoader.