Condividi tramite


Dizionari di risorse

Il .NET Multi-platform App UI (.NET MAUI) ResourceDictionary è un repository per le risorse utilizzate da un'app .NET MAUI. Le risorse tipiche archiviate in un ResourceDictionary includono stili, modelli di controllo, modelli di dati, convertitori e colori.

È possibile fare riferimento alle risorse XAML archiviate in un oggetto ResourceDictionary e applicarle agli elementi usando l'estensione di markup StaticResource o DynamicResource. In C#, le risorse possono anche essere definite in un ResourceDictionary e a cui si può fare riferimento, applicandole agli elementi usando un indicizzatore basato su stringa.

Suggerimento

In Visual Studio, un file basato su XAML, supportato da un file code-behind, può essere aggiunto al tuo progetto mediante il modello di elemento .NET MAUI ResourceDictionary (XAML).

Creare le risorse

Ogni oggetto derivato di VisualElement ha una proprietà Resources, che è un ResourceDictionary che può contenere risorse. Analogamente, un oggetto derivato Application ha una proprietà Resources, che è un ResourceDictionary che può contenere risorse.

Un'app .NET MAUI può contenere solo una singola classe che deriva da Application, ma spesso fa uso di molte classi che derivano da VisualElement, comprese pagine, layout e viste. Ognuno di questi oggetti può avere la sua proprietà Resources impostata su un ResourceDictionary contenente risorse. Scegliere dove mettere un particolare ResourceDictionary influisce su dove le risorse possono essere utilizzate.

  • Le risorse in un ResourceDictionary che è associato a una vista, come un Button o un Label, possono essere applicate solo a quell'oggetto specifico.
  • Le risorse in un ResourceDictionary layout collegato a un layout, ad esempio StackLayout o Grid, possono essere applicate al layout e a tutti gli elementi figlio di tale layout.
  • Le risorse definite a livello di pagina possono essere applicate alla pagina e a tutte le sue sottopagine.
  • Risorse in ResourceDictionary definite a livello di applicazione possono essere applicate in tutta l'app.

Ad eccezione degli stili impliciti, ogni risorsa nel dizionario delle risorse deve avere una chiave stringa univoca definita con l'attributo x:Key.

Il codice XAML seguente mostra le risorse definite a livello di applicazione ResourceDictionary nel file App.xaml:

<Application xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="ResourceDictionaryDemo.App">
    <Application.Resources>

        <Thickness x:Key="PageMargin">20</Thickness>

        <!-- Colors -->
        <Color x:Key="AppBackgroundColor">AliceBlue</Color>
        <Color x:Key="NavigationBarColor">#1976D2</Color>
        <Color x:Key="NavigationBarTextColor">White</Color>
        <Color x:Key="NormalTextColor">Black</Color>

        <!-- Images -->
        <x:String x:Key="BackgroundImage">background</x:String>
        <x:String x:Key="MenuIcon">menu.png</x:String>
        <x:String x:Key="SearchIcon">search.png</x:String>

        <!-- Implicit styles -->
        <Style TargetType="NavigationPage">
            <Setter Property="BarBackgroundColor"
                    Value="{StaticResource NavigationBarColor}" />
            <Setter Property="BarTextColor"
                    Value="{StaticResource NavigationBarTextColor}" />
        </Style>

        <Style TargetType="ContentPage"
               ApplyToDerivedTypes="True">
            <Setter Property="BackgroundColor"
                    Value="{StaticResource AppBackgroundColor}" />
        </Style>

    </Application.Resources>
</Application>

In questo esempio, il dizionario risorse definisce una risorsa Thickness, più risorse Color, e due risorse implicite Style.

Importante

L'inserimento di risorse direttamente tra i tag dell'elemento Resources proprietà crea automaticamente un ResourceDictionary oggetto . Tuttavia, è anche valido inserire tutte le risorse tra tag opzionali ResourceDictionary.

Utilizzare le risorse

Ogni risorsa ha una chiave che è specificata usando l'attributo x:Key, che diventa la sua chiave nel dizionario nel ResourceDictionary. La chiave viene usata per fare riferimento a una risorsa dal ResourceDictionary con l'estensione di markup XAML StaticResource o DynamicResource.

L'estensione di markup StaticResource è simile all'estensione di markup DynamicResource in quanto entrambi usano una chiave del dizionario per fare riferimento a un valore da un dizionario risorse. Tuttavia, mentre l'estensione StaticResource di markup esegue una singola ricerca nel dizionario, l'estensione DynamicResource di markup mantiene un collegamento con la chiave del dizionario. Pertanto, se la voce del dizionario associata alla chiave viene sostituita, la modifica viene applicata all'elemento visivo. In questo modo è possibile apportare modifiche alle risorse di runtime in un'app. Per ulteriori informazioni sulle estensioni di markup, consultare estensioni di markup XAML.

L'esempio XAML seguente mostra come consumare le risorse e definire una risorsa aggiuntiva in un oggetto StackLayout:

<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="ResourceDictionaryDemo.MainPage"
             Title="Main page">
    <StackLayout Margin="{StaticResource PageMargin}"
                 Spacing="6">
        <StackLayout.Resources>
            <!-- Implicit style -->
            <Style TargetType="Button">
                <Setter Property="FontSize" Value="14" />
                <Setter Property="BackgroundColor" Value="#1976D2" />
                <Setter Property="TextColor" Value="White" />
                <Setter Property="CornerRadius" Value="5" />
            </Style>
        </StackLayout.Resources>

        <Label Text="This app demonstrates consuming resources that have been defined in resource dictionaries." />
        <Button Text="Navigate"
                Clicked="OnNavigateButtonClicked" />
    </StackLayout>
</ContentPage>

In questo esempio, l'oggetto ContentPage utilizza lo stile predefinito definito nel dizionario delle risorse a livello dell'applicazione. L'oggetto StackLayout utilizza la PageMargin risorsa definita nel dizionario risorse a livello di applicazione, mentre l'oggetto Button utilizza lo stile implicito definito nel StackLayout dizionario risorse. Ciò comporta l'aspetto illustrato nello screenshot seguente:

Utilizzo delle risorse del dizionario di risorse.

Importante

Le risorse specifiche di una singola pagina non devono essere incluse in un dizionario risorse a livello di applicazione, in quanto tali risorse verranno quindi analizzate all'avvio dell'app anziché quando richiesto da una pagina. Per ulteriori informazioni, consultare Ridurre le dimensioni del dizionario delle risorse dell'applicazione.

Comportamento di ricerca delle risorse

Il seguente processo di individuazione avviene quando viene fatto riferimento a una risorsa con l'estensione di markup StaticResource o DynamicResource.

  • La chiave richiesta viene verificata nel dizionario risorse, se esistente, per l'elemento che imposta la proprietà. Se viene trovata la chiave richiesta, viene restituito il relativo valore e il processo di ricerca termina.
  • Se non viene trovata una corrispondenza, il processo di ricerca cerca la struttura ad albero visuale verso l'alto, controllando il dizionario risorse di ogni elemento padre. Se viene trovata la chiave richiesta, viene restituito il relativo valore e il processo di ricerca termina. In caso contrario, il processo continua verso l'alto fino a quando non viene raggiunto l'elemento radice.
  • Se non viene trovata una corrispondenza nell'elemento radice, viene esaminato il dizionario risorse a livello di applicazione.
  • Se non viene ancora trovata una corrispondenza, viene generata un'eccezione XamlParseException .

Pertanto, quando il parser XAML rileva un'estensione StaticResource o DynamicResource di markup, cerca una chiave corrispondente risalendo l'albero visuale, utilizzando la prima corrispondenza trovata. Se la ricerca termina sulla pagina e la chiave ancora non è stata trovata, il parser XAML effettua la ricerca nell'oggetto ResourceDictionary attaccato all'oggetto App. Se la chiave non viene ancora trovata, viene generata un'eccezione.

Eseguire l'override delle risorse

Quando le risorse condividono le chiavi, le risorse definite più in basso nella struttura ad albero visuale avranno la precedenza su quelle definite più in alto. Ad esempio, l'impostazione di una risorsa a livello AppBackgroundColor su AliceBlue verrà sostituita da una risorsa a livello AppBackgroundColor impostata su Teal. Analogamente, una risorsa a livello di pagina verrà sostituita da una risorsa a livello AppBackgroundColor di layout o di vista AppBackgroundColor.

Dizionari di risorse autonomi

Un ResourceDictionary può anche essere creato come file XAML autonomo che non ha un file code-behind associato. Per creare un oggetto autonomo ResourceDictionary, aggiungere un nuovo ResourceDictionary file al progetto con il modello di elemento ResourceDictionary (XAML) di .NET MAUI ed eliminare il relativo file code-behind. Quindi, nel file XAML, rimuovere l'attributo x:Class dal tag ResourceDictionary vicino all'inizio del file. Aggiungere anche <?xaml-comp compile="true" ?> dopo l'intestazione XML per assicurarsi che il XAML sia compilato.

Un oggetto ResourceDictionary può anche essere creato come file XAML autonomo che non è accompagnato da un file code-behind. Per creare un oggetto autonomo ResourceDictionary, aggiungere un nuovo ResourceDictionary file al progetto con il modello di elemento ResourceDictionary (XAML) di .NET MAUI ed eliminare il relativo file code-behind. Quindi, nel file XAML rimuovere l'attributo x:Class dal tag ResourceDictionary vicino all'inizio del file. Per impostazione predefinita, un ResourceDictionary ha il suo codice XAML compilato, a meno che <?xaml-comp compile="false" ?> sia specificato dopo l'intestazione XML.

Nota

Un ResourceDictionary stand-alone deve avere un'azione di compilazione MauiXaml.

L'esempio XAML seguente mostra un esempio autonomo ResourceDictionary denominato MyResourceDictionary.xaml:

<?xml version="1.0" encoding="UTF-8" ?>
<ResourceDictionary xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
                    xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
                    xmlns:local="clr-namespace:ResourceDictionaryDemo">
    <DataTemplate x:Key="PersonDataTemplate"
                  x:DataType="local:Person">
        <ViewCell>
            <Grid RowSpacing="6"
                  ColumnSpacing="6">
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="0.5*" />
                    <ColumnDefinition Width="0.2*" />
                    <ColumnDefinition Width="0.3*" />
                </Grid.ColumnDefinitions>
                <Label Text="{Binding Name}"
                       TextColor="{StaticResource NormalTextColor}"
                       FontAttributes="Bold" />
                <Label Grid.Column="1"
                       Text="{Binding Age}"
                       TextColor="{StaticResource NormalTextColor}" />
                <Label Grid.Column="2"
                       Text="{Binding Location}"
                       TextColor="{StaticResource NormalTextColor}"
                       HorizontalTextAlignment="End" />
            </Grid>
        </ViewCell>
    </DataTemplate>
</ResourceDictionary>

In questo esempio, il ResourceDictionary contiene una singola risorsa, ovvero un oggetto di tipo DataTemplate. MyResourceDictionary.xaml può essere utilizzato unendolo in un altro dizionario risorse.

Unisci dizionari risorse

I dizionari risorse possono essere combinati unendo uno o più ResourceDictionary oggetti in un altro ResourceDictionaryoggetto .

Unire i dizionari delle risorse locali

Un file locale ResourceDictionary può essere unito a un altro ResourceDictionary creando un ResourceDictionary oggetto la cui Source proprietà è impostata sul nome file del file XAML con le risorse:

<ContentPage ...>
    <ContentPage.Resources>
        <!-- Add more resources here -->
        <ResourceDictionary Source="MyResourceDictionary.xaml" />
        <!-- Add more resources here -->
    </ContentPage.Resources>
    ...
</ContentPage>

Questa sintassi non istanzia la classe MyResourceDictionary. Fa invece riferimento al file XAML. Per questo motivo, quando si imposta la Source proprietà, non è necessario un file code-behind e l'attributo x:Class può essere rimosso dal tag radice del MyResourceDictionary.xaml file.

Importante

La ResourceDictionary.Source property può essere impostata solo da XAML.

Unire dizionari delle risorse di altri assembly

Un ResourceDictionary oggetto può anche essere unito in un altro ResourceDictionary aggiungendolo nella MergedDictionaries proprietà di ResourceDictionary. Questa tecnica consente di unire i dizionari delle risorse, indipendentemente dall'assembly in cui risiedono. L'unione di dizionari delle risorse da assembly esterni richiede che il ResourceDictionary abbia un'azione di compilazione impostata su MauiXaml, che ci sia un file code-behind, e che l'attributo x:Class sia definito nel tag radice del file.

Avviso

La classe ResourceDictionary definisce anche una proprietà MergedWith. Tuttavia, questa proprietà è stata deprecata e non deve più essere utilizzata.

L'esempio di codice seguente mostra due dizionari di risorse aggiunti alla raccolta MergedDictionaries a livello di pagina ResourceDictionary.

<ContentPage ...
             xmlns:local="clr-namespace:ResourceDictionaryDemo"
             xmlns:theme="clr-namespace:MyThemes;assembly=MyThemes">
    <ContentPage.Resources>
        <ResourceDictionary>
            <!-- Add more resources here -->
            <ResourceDictionary.MergedDictionaries>
                <!-- Add more resource dictionaries here -->
                <local:MyResourceDictionary />
                <theme:DefaultTheme />
                <!-- Add more resource dictionaries here -->
            </ResourceDictionary.MergedDictionaries>
            <!-- Add more resources here -->
        </ResourceDictionary>
    </ContentPage.Resources>
    ...
</ContentPage>

In questo esempio, un dizionario risorse dello stesso assembly e un dizionario risorse di un assembly esterno vengono uniti nel dizionario risorse a livello di pagina. Inoltre, è anche possibile aggiungere altri ResourceDictionary oggetti all'interno dei tag MergedDictionaries property-element e altre risorse all'esterno di tali tag.

Importante

In un ResourceDictionary può essere presente solo un MergedDictionaries tag elemento proprietà, ma è possibile inserire tutti gli oggetti ResourceDictionary in tale elemento come necessario.

Quando le risorse unite ResourceDictionary condividono valori di attributo identici x:Key , .NET MAUI usa la precedenza delle risorse seguente:

  1. Risorse locali del dizionario risorse.
  2. Le risorse contenute nei dizionari risorse unite tramite la MergedDictionaries raccolta, nell'ordine inverso in cui sono elencate nella MergedDictionaries proprietà.

Suggerimento

La ricerca di dizionari risorse può essere un'attività a elevato utilizzo di calcolo se un'app contiene più dizionari di risorse di grandi dimensioni. Pertanto, per evitare ricerche non necessarie, è necessario assicurarsi che ogni pagina in un'applicazione usi solo dizionari risorse appropriati per la pagina.

Usare un dizionario di risorse basato su XAML dal codice

I dizionari di risorse definiti in XAML possono essere utilizzati nel codice, purché il ResourceDictionary sia supportato da un file code-behind. In Visual Studio, i file basati su XAML che sono supportati da file code-behind possono essere aggiunti al tuo progetto dal modello di elemento .NET MAUI ResourceDictionary (XAML).

Screenshot of resource dictionaries backed by code-behind.Screenshot dei dizionari delle risorse supportati da code-behind.

I dizionari di risorse basati su XAML accompagnati da file code-behind possono quindi essere utilizzati in C# aggiungendoli nella MergedDictionaries collezione del dizionario di risorse:

Resources.MergedDictionaries.Add(new MyMauiApp.Resources.Styles.MyColors());
Resources.MergedDictionaries.Add(new MyMauiApp.Resources.Styles.MyStyles());

Accedere alle risorse in base alla chiave dal codice

È possibile accedere alle risorse in un dizionario risorse dal codice come qualsiasi altro dizionario.

L'esempio seguente illustra come recuperare e applicare una risorsa dal dizionario risorse di una pagina:

// Retrieve the Primary color value which is in the page's resource dictionary
var hasValue = Resources.TryGetValue("Primary", out object primaryColor);

if (hasValue)
{
    myLabel.TextColor = (Color)primaryColor;
}

Questo è l'approccio consigliato che garantisce che .NET MAUI non generi una KeyNotFoundException se non è in grado di recuperare una risorsa dal codice. Ciò può verificarsi quando un dizionario risorse unito è costituito da risorse definite in un file XAML e risorse inline. Per ulteriori informazioni, vedere Problema di GitHub n. 11214.

Nota

Per recuperare le risorse a livello di app dal codice, accedere al dizionario delle risorse App.Current.Resources.