Xamarin.Forms dizionari risorse

Download Sample Scaricare l'esempio

Un ResourceDictionary è un repository per le risorse usate da un'applicazione Xamarin.Forms . Le risorse tipiche archiviate in un ResourceDictionary oggetto includono stili, modelli di controllo, modelli di dati, colori e convertitori.

In XAML è possibile fare riferimento alle risorse archiviate in un ResourceDictionary oggetto e applicarle agli elementi usando l'estensione StaticResource di markup o DynamicResource . In C# le risorse possono anche essere definite in un ResourceDictionary oggetto e quindi a cui si fa riferimento e applicate agli elementi usando un indicizzatore basato su stringa. Tuttavia, l'uso di in ResourceDictionary C# può risultare poco vantaggioso, poiché gli oggetti condivisi possono essere archiviati come campi o proprietà ed è possibile accedervi direttamente senza dover prima recuperarli da un dizionario.

Creare risorse in XAML

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

Un'applicazione Xamarin.Forms contiene solo una classe che deriva da Application, ma spesso usa molte classi che derivano da VisualElement, incluse pagine, layout e controlli. Uno di questi oggetti può avere la relativa Resources proprietà impostata su un ResourceDictionary oggetto contenente le risorse. Scelta della posizione in cui inserire un impatto particolare ResourceDictionary in cui è possibile usare le risorse:

  • Le risorse in un oggetto ResourceDictionary collegato a una vista, ad esempio Button o Label , possono essere applicate solo a tale oggetto specifico.
  • Le risorse in un ResourceDictionary layout collegato a un layout, StackLayout ad esempio o Grid , possono essere applicate al layout e a tutti gli elementi figlio di tale layout.
  • Le risorse in un ResourceDictionary oggetto definito a livello di pagina possono essere applicate alla pagina e a tutti i relativi elementi figlio.
  • Le risorse in un ResourceDictionary definito a livello di applicazione possono essere applicate in tutta l'applicazione.

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

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

<Application xmlns="http://xamarin.com/schemas/2014/forms"
             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>

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

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

    </Application.Resources>
</Application>

In questo esempio il dizionario risorse definisce una Thickness risorsa, più Color risorse e due risorse implicite Style . Per altre informazioni sulla App classe, vedere Xamarin.Forms Classe app.

Nota

È anche possibile inserire tutte le risorse tra tag espliciti ResourceDictionary . Tuttavia, poiché Xamarin.Forms 3.0 i ResourceDictionary tag non sono necessari. L'oggetto ResourceDictionary viene invece creato automaticamente ed è possibile inserire le risorse direttamente tra i tag dell'elemento Resources proprietà.

Usare le risorse in XAML

Ogni risorsa ha una chiave specificata usando l'attributo x:Key , che diventa la chiave del dizionario in ResourceDictionary. La chiave viene usata per fare riferimento a una risorsa da con l'estensione ResourceDictionaryStaticResource di markup o DynamicResource .

L'estensione StaticResource di markup è simile all'estensione DynamicResource di markup 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 ricerca in un singolo dizionario, l'estensione DynamicResource di markup mantiene un collegamento alla chiave del dizionario. Pertanto, se la voce del dizionario associata alla chiave viene sostituita, la modifica viene applicata all'elemento visivo. Ciò consente di apportare modifiche alle risorse di runtime in un'applicazione. Per altre informazioni sulle estensioni di markup, vedi Estensioni di markup XAML.

L'esempio XAML seguente illustra come usare le risorse e definisce anche risorse aggiuntive in un StackLayoutoggetto :

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="ResourceDictionaryDemo.HomePage"
             Title="Home Page">
    <StackLayout Margin="{StaticResource PageMargin}">
        <StackLayout.Resources>
            <!-- Implicit style -->
            <Style TargetType="Button">
                <Setter Property="FontSize" Value="Medium" />
                <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 implicito definito nel dizionario risorse a livello di 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. Il risultato è l'aspetto illustrato negli screenshot seguenti:

Consuming ResourceDictionary Resources

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'applicazione anziché quando richiesto da una pagina. Per altre informazioni, vedere Ridurre le dimensioni del dizionario risorse dell'applicazione.

Comportamento di ricerca delle risorse

Il processo di ricerca seguente si verifica quando viene fatto riferimento a una risorsa con l'estensione StaticResource di markup 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 di markup o DynamicResource , cerca una chiave corrispondente passando attraverso la struttura ad albero visuale, usando la prima corrispondenza trovata. Se la ricerca termina nella pagina e la chiave non è ancora stata trovata, il parser XAML cerca nell'oggetto ResourceDictionaryApp associato. 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 AppBackgroundColor risorsa su AliceBlue a livello di applicazione verrà sostituita da una risorsa a livello AppBackgroundColor di pagina impostata su Teal. Analogamente, una risorsa a livello AppBackgroundColor di pagina verrà sostituita da una risorsa a livello AppBackgroundColor di controllo.

Dizionari risorse autonomi

Una classe derivata da ResourceDictionary può anche trovarsi in un file XAML autonomo. Il file XAML può quindi essere condiviso tra le applicazioni.

Per creare un file di questo tipo, aggiungere un nuovo elemento Visualizzazione contenuto o Pagina contenuto al progetto (ma non una visualizzazione contenuto o una pagina contenuto con solo un file C#). Eliminare il file code-behind e nel file XAML modificare il nome della classe di base da ContentView o ContentPage in ResourceDictionary. Rimuovere inoltre l'attributo x:Class dal tag radice del file.

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

<ResourceDictionary xmlns="http://xamarin.com/schemas/2014/forms"
                    xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml">
    <DataTemplate x:Key="PersonDataTemplate">
        <ViewCell>
            <Grid>
                <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 l'oggetto ResourceDictionary contiene una singola risorsa, ovvero un oggetto di tipo DataTemplate. MyResourceDictionary.xaml può essere utilizzato unendolo in un altro dizionario risorse.

Per impostazione predefinita, il linker rimuoverà i file XAML autonomi dalle build di rilascio quando il comportamento del linker è impostato per collegare tutti gli assembly. Per garantire che i file XAML autonomi rimangano in una build di versione:

  1. Aggiungere un attributo personalizzato Preserve all'assembly contenente i file XAML autonomi. Per altre informazioni, vedere Conservazione del codice.

  2. Impostare l'attributo Preserve a livello di assembly:

    [assembly:Preserve(AllMembers = true)]
    

Per altre informazioni sul collegamento, vedere Collegamento di app Xamarin.iOS e collegamento in Android.

Dizionari risorse uniti

I dizionari risorse uniti combinano uno o più ResourceDictionary oggetti in un altro ResourceDictionaryoggetto .

Unire dizionari 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 crea un'istanza della MyResourceDictionary classe . 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 file MyResourceDictionary.xaml .

Importante

La Source proprietà può essere impostata solo da XAML.

Unire dizionari risorse da 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 risorse da assembly esterni richiede che sia ResourceDictionary impostata un'azione di compilazione su EmbeddedResource, che disponga di un file code-behind e di definire l'attributo x:Class nel tag radice del file.

Avviso

Anche la classe ResourceDictionary definisce 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 MergedDictionaries raccolta di un livello ResourceDictionarydi pagina:

<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:LightTheme />
                <!-- 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 MergedDictionaries tag property-element e altre risorse all'esterno di tali tag.

Importante

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

Quando le risorse unite ResourceDictionary condividono valori di attributo identici x:Key , Xamarin.Forms usa la precedenza della risorsa 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à .

Nota

La ricerca di dizionari risorse può essere un'attività a elevato utilizzo di calcolo se un'applicazione 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.

Altri video di Xamarin sono disponibili su Channel 9 e YouTube.