Resource Dictionaries

Download Sample Download the sample

XAML resources are definitions of objects that can be shared and re-used throughout a Xamarin.Forms application.

These resource objects are stored in a resource dictionary. This article describes how to create and consume a resource dictionary, and how to merge resource dictionaries.

Overview

A ResourceDictionary is a repository for resources that are used by a Xamarin.Forms application. Typical resources that are stored in a ResourceDictionary include styles, control templates, data templates, colors, and converters.

In XAML, resources that are stored in a ResourceDictionary can then be retrieved and applied to elements by using the StaticResource markup extension. In C#, resources can also be defined in a ResourceDictionary and then retrieved and applied to elements by using a string-based indexer. However, there's little advantage to using a ResourceDictionary in C#, as shared objects can simply be stored as fields or properties, and accessed directly without having to first retrieve them from a dictionary.

Creating and Consuming a ResourceDictionary

Resources are defined in a ResourceDictionary that is then set to one of the following Resources properties:

A Xamarin.Forms program contains only one class that derives from Application but often makes use of many classes that derive from VisualElement, including pages, layouts, and controls. Any of these objects can have its Resources property set to a ResourceDictionary. Choosing where to put a particular ResourceDictionary impacts where the resources can be used:

  • Resources in a ResourceDictionary that is attached to a view such as Button or Label can only be applied to that particular object, so this is not very useful.
  • Resources in a ResourceDictionary attached to a layout such as StackLayout or Grid can be applied to the layout and all the children of that layout.
  • Resources in a ResourceDictionary defined at the page level can be applied to the page and to all its children.
  • Resources in a ResourceDictionary defined at the application level can be applied throughout the application.

The following XAML shows resources defined in an application level ResourceDictionary in the App.xaml file created as part of the standard Xamarin.Forms program:

<Application ...>
    <Application.Resources>
        <ResourceDictionary>
            <Color x:Key="PageBackgroundColor">Yellow</Color>
            <Color x:Key="HeadingTextColor">Black</Color>
            <Color x:Key="NormalTextColor">Blue</Color>
            <Style x:Key="LabelPageHeadingStyle" TargetType="Label">
                <Setter Property="FontAttributes" Value="Bold" />
                <Setter Property="HorizontalOptions" Value="Center" />
                <Setter Property="TextColor" Value="{StaticResource HeadingTextColor}" />
            </Style>
        </ResourceDictionary>
    </Application.Resources>
</Application>

This ResourceDictionary defines three Color resources and a Style resource. For more information about the App class, see App Class.

Beginning in Xamarin.Forms 3.0, the explicit ResourceDictionary tags are not required. The ResourceDictionary object is created automatically, and you can insert the resources directly between the Resources property-element tags:

<Application ...>
    <Application.Resources>
        <Color x:Key="PageBackgroundColor">Yellow</Color>
        <Color x:Key="HeadingTextColor">Black</Color>
        <Color x:Key="NormalTextColor">Blue</Color>
        <Style x:Key="LabelPageHeadingStyle" TargetType="Label">
            <Setter Property="FontAttributes" Value="Bold" />
            <Setter Property="HorizontalOptions" Value="Center" />
            <Setter Property="TextColor" Value="{StaticResource HeadingTextColor}" />
        </Style>
    </Application.Resources>
</Application>

Each resource has a key that is specified using the x:Key attribute, which becomes it dictionary key in the ResourceDictionary. The key is used to retrieve a resource from the ResourceDictionary by the StaticResource markup extension, as demonstrated in the following XAML code example that shows additional resources defined within the StackLayout:

<StackLayout Margin="0,20,0,0">
  <StackLayout.Resources>
    <ResourceDictionary>
      <Style x:Key="LabelNormalStyle" TargetType="Label">
        <Setter Property="TextColor" Value="{StaticResource NormalTextColor}" />
      </Style>
      <Style x:Key="MediumBoldText" TargetType="Button">
        <Setter Property="FontSize" Value="Medium" />
        <Setter Property="FontAttributes" Value="Bold" />
      </Style>
    </ResourceDictionary>
  </StackLayout.Resources>
  <Label Text="ResourceDictionary Demo" Style="{StaticResource LabelPageHeadingStyle}" />
    <Label Text="This app demonstrates consuming resources that have been defined in resource dictionaries."
           Margin="10,20,10,0"
           Style="{StaticResource LabelNormalStyle}" />
    <Button Text="Navigate"
            Clicked="OnNavigateButtonClicked"
            TextColor="{StaticResource NormalTextColor}"
            Margin="0,20,0,0"
            HorizontalOptions="Center"
            Style="{StaticResource MediumBoldText}" />
</StackLayout>

The first Label instance retrieves and consumes the LabelPageHeadingStyle resource defined in the application level ResourceDictionary, with the second Label instance retrieving and consuming the LabelNormalStyle resource defined in the control level ResourceDictionary. Similarly, the Button instance retrieves and consumes the NormalTextColor resource defined in the application level ResourceDictionary, and the MediumBoldText resource defined in the control level ResourceDictionary. This results in the appearance shown in the following screenshots:

Note

Resources that are specific to a single page shouldn't be included in an application level resource dictionary, as such resources will then be parsed at application startup instead of when required by a page. For more information, see Reduce the Application Resource Dictionary Size.

Overriding Resources

When ResourceDictionary resources share x:Key attribute values, resources defined lower in the view hierarchy will take precedence over those defined higher up. For example, setting the PageBackgroundColor resource to Blue at the application level will be overridden by a page level PageBackgroundColor resource set to Yellow. Similarly, a page level PageBackgroundColor resource will be overridden by a control level PageBackgroundColor resource. This precedence is demonstrated by the following XAML code example:

<ContentPage ... BackgroundColor="{StaticResource PageBackgroundColor}">
    <ContentPage.Resources>
        <ResourceDictionary>
            <Color x:Key="PageBackgroundColor">Blue</Color>
            <Color x:Key="NormalTextColor">Yellow</Color>
        </ResourceDictionary>
    </ContentPage.Resources>
    <StackLayout Margin="0,20,0,0">
        ...
        <Label Text="ResourceDictionary Demo" Style="{StaticResource LabelPageHeadingStyle}" />
        <Label Text="This app demonstrates consuming resources that have been defined in resource dictionaries."
               Margin="10,20,10,0"
               Style="{StaticResource LabelNormalStyle}" />
        <Button Text="Navigate"
                Clicked="OnNavigateButtonClicked"
                TextColor="{StaticResource NormalTextColor}"
                Margin="0,20,0,0"
                HorizontalOptions="Center"
                Style="{StaticResource MediumBoldText}" />
    </StackLayout>
</ContentPage>

The original PageBackgroundColor and NormalTextColor instances, defined at the application level, are overridden by the PageBackgroundColor and NormalTextColor instances defined at page level. Therefore, the page background color becomes blue, and the text on the page becomes yellow, as demonstrated in the following screenshots:

However, note that the background bar of the NavigationPage is still yellow, because the BarBackgroundColor property is set to the value of the PageBackgroundColor resource defined in the application level ResourceDictionary.

Here's another way to think about ResourceDictionary precedence: When the XAML parser encounters a StaticResource, it searches for a matching key by traveling up through the visual tree, using the first match it finds. If this search ends at the page and the key still hasn't been found, the XAML parser searches the ResourceDictionary attached to the App object. If the key is still not found, an exception is raised.

Stand-alone Resource Dictionaries

A class derived from ResourceDictionary can also be in a separate stand-alone file. (More precisely, a class derived from ResourceDictionary generally requires a pair of files because the resources are defined in a XAML file but a code-behind file with an InitializeComponent call is also necessary.) The resultant file can then be shared among applications.

To create such a file, add a new Content View or Content Page item to the project (but not a Content View or Content Page with only a C# file). In both the XAML file and C# file, change the name of the base class from ContentView or ContentPage to ResourceDictionary. In the XAML file, the name of the base class is the top-level element.

The following XAML example shows a ResourceDictionary named MyResourceDictionary:

<ResourceDictionary xmlns="http://xamarin.com/schemas/2014/forms"
                    xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
                    x:Class="ResourceDictionaryDemo.MyResourceDictionary">
    <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>

This ResourceDictionary contains a single resource, which is an object of type DataTemplate.

You can instantiate MyResourceDictionary by putting it between a pair of Resources property-element tags, for example, in a ContentPage:

<ContentPage ...>
    <ContentPage.Resources>
        <local:MyResourceDictionary />
    </ContentPage.Resources>
    ...
</ContentPage>

An instance of MyResourceDictionary is set to the Resources property of the ContentPage object.

However, this approach has some limitations: The Resources property of the ContentPage references only this one ResourceDictionary. In most cases, you want the option of including other ResourceDictionary instances and perhaps other resources as well.

This task requires merged resource dictionaries.

Merged Resource Dictionaries

Merged resource dictionaries combine one or more ResourceDictionary instances into another ResourceDictionary. You can do this in a XAML file by setting the MergedDictionaries property to one or more resource dictionaries that will be merged into the application, page, or control level ResourceDictionary.

Important

ResourceDictionary also defines a MergedWith property. Do not use this property; it has been deprecated as of Xamarin.Forms 3.0.

An instance of MyResourceDictionary can be merged into any application, page, or control level ResourceDictionary. The following XAML code example shows it being merged into a page level ResourceDictionary using the MergedDictionaries property:

<ContentPage ...>
    <ContentPage.Resources>
        <ResourceDictionary>
            <ResourceDictionary.MergedDictionaries>
                <local:MyResourceDictionary />
            </ResourceDictionary.MergedDictionaries>
        </ResourceDictionary>
    </ContentPage.Resources>
    ...
</ContentPage>

That markup shows only an instance of MyResourceDictionary being added to the ResourceDictionary but you can also reference other ResourceDictionary instances within the MergedDictionary property-element tags, and other resources outside of those tags:

<ContentPage ...>
    <ContentPage.Resources>
        <ResourceDictionary>

            <!-- Add more resources here -->

            <ResourceDictionary.MergedDictionaries>

                <!-- Add more resource dictionaries here -->

                <local:MyResourceDictionary />

                <!-- Add more resource dictionaries here -->

            </ResourceDictionary.MergedDictionaries>

            <!-- Add more resources here -->

        </ResourceDictionary>
    </ContentPage.Resources>
    ...
</ContentPage>

There can be only one MergedDictionaries section in a ResourceDictionary, but you can put as many ResourceDictionary instances in there as you want.

When merged ResourceDictionary resources share identical x:Key attribute values, Xamarin.Forms uses the following resource precedence:

  1. The resources local to the resource dictionary.
  2. The resources contained in the resource dictionary that was merged via the deprecated MergedWith property.
  3. The resources contained in the resource dictionaries that were merged via the MergedDictionaries collection, in the reverse order they are listed in the MergedDictionaries property.

Note

Searching resource dictionaries can be a computationally intensive task if an application contains multiple, large resource dictionaries. Therefore, to avoid unnecessary searching, you should ensure that each page in an application only uses resource dictionaries that are appropriate to the page.

Merging Dictionaries in Xamarin.Forms 3.0

Beginning with Xamarin.Forms 3.0, the process of merging ResourceDictionary instances has become somewhat easier and more flexible. The MergedDictionaries property-element tags are no longer necessary. Instead, you add to the resource dictionary another ResourceDictionary tag with the new Source property set to the filename of the XAML file with the resources:

<ContentPage ...>
    <ContentPage.Resources>
        <ResourceDictionary>

            <!-- Add more resources here -->

            <ResourceDictionary Source="MyResourceDictionary.xaml" />

            <!-- Add more resources here -->

        </ResourceDictionary>
    </ContentPage.Resources>
    ...
</ContentPage>

Because Xamarin.Forms 3.0 automatically instantiates the ResourceDictionary, those two outer ResourceDictionary tags are no longer required:

<ContentPage ...>
    <ContentPage.Resources>

        <!-- Add more resources here -->

        <ResourceDictionary Source="MyResourceDictionary.xaml" />

        <!-- Add more resources here -->

    </ContentPage.Resources>
    ...
</ContentPage>

This new syntax does not instantiate the MyResourceDictionary class. Instead, it references the XAML file. For that reason the code-behind file (MyResourceDictionary.xaml.cs) is no longer required. You can also remove the x:Class attribute from the root tag of the MyResourceDictionary.xaml file.

Summary

This article explained how to create and consume a ResourceDictionary, and how to merge resource dictionaries. A ResourceDictionary allows resources to be defined in a single location, and re-used throughout a Xamarin.Forms application.