Xamarin.Forms resource dictionaries
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 be referenced and applied to elements by using the StaticResource
or DynamicResource
markup extension. In C#, resources can also be defined in a ResourceDictionary
and then referenced 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 be stored as fields or properties, and accessed directly without having to first retrieve them from a dictionary.
Create resources in XAML
Every VisualElement
derived object has a Resources
property, which is a ResourceDictionary
that can contain resources. Similarly, an Application
derived object has a Resources
property, which is a ResourceDictionary
that can contain resources.
A Xamarin.Forms application contains only 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
containing resources. 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 asButton
orLabel
can only be applied to that particular object. - Resources in a
ResourceDictionary
attached to a layout such asStackLayout
orGrid
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.
With the exception of implicit styles, each resource in resource dictionary must have a unique string key that's defined with the x:Key
attribute.
The following XAML shows resources defined in an application level ResourceDictionary
in the App.xaml file:
<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 this example, the resource dictionary defines a Thickness
resource, multiple Color
resources, and two implicit Style
resources. For more information about the App
class, see Xamarin.Forms App Class.
Note
It's also valid to place all resources between explicit ResourceDictionary
tags. However, since Xamarin.Forms 3.0 the ResourceDictionary
tags are not required. Instead, the ResourceDictionary
object is created automatically, and you can insert the resources directly between the Resources
property-element tags.
Consume resources in XAML
Each resource has a key that is specified using the x:Key
attribute, which becomes its dictionary key in the ResourceDictionary
. The key is used to reference a resource from the ResourceDictionary
with the StaticResource
or DynamicResource
markup extension.
The StaticResource
markup extension is similar to the DynamicResource
markup extension in that both use a dictionary key to reference a value from a resource dictionary. However, while the StaticResource
markup extension performs a single dictionary lookup, the DynamicResource
markup extension maintains a link to the dictionary key. Therefore, if the dictionary entry associated with the key is replaced, the change is applied to the visual element. This enables runtime resource changes to be made in an application. For more information about markup extensions, see XAML Markup Extensions.
The following XAML example shows how to consume resources, and also defines additional resources in a StackLayout
:
<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 this example, the ContentPage
object consumes the implicit style defined in the application level resource dictionary. The StackLayout
object consumes the PageMargin
resource defined in the application level resource dictionary, while the Button
object consumes the implicit style defined in the StackLayout
resource dictionary. This results in the appearance shown in the following screenshots:
Important
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.
Resource lookup behavior
The following lookup process occurs when a resource is referenced with the StaticResource
or DynamicResource
markup extension:
- The requested key is checked for in the resource dictionary, if it exists, for the element that sets the property. If the requested key is found, its value is returned and the lookup process terminates.
- If a match isn't found, the lookup process searches the visual tree upwards, checking the resource dictionary of each parent element. If the requested key is found, its value is returned and the lookup process terminates. Otherwise the process continues upwards until the root element is reached.
- If a match isn't found at the root element, the application level resource dictionary is examined.
- If a match still isn't found, a
XamlParseException
is thrown.
Therefore, when the XAML parser encounters a StaticResource
or DynamicResource
markup extension, 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 thrown.
Override resources
When resources share keys, resources defined lower in the visual tree will take precedence over those defined higher up. For example, setting an AppBackgroundColor
resource to AliceBlue
at the application level will be overridden by a page level AppBackgroundColor
resource set to Teal
. Similarly, a page level AppBackgroundColor
resource will be overridden by a control level AppBackgroundColor
resource.
Stand-alone resource dictionaries
A class derived from ResourceDictionary
can also be in a stand-alone XAML file. The XAML 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). Delete the code-behind file, and in the XAML file change the name of the base class from ContentView
or ContentPage
to ResourceDictionary
. In addition, remove the x:Class
attribute from the root tag of the file.
The following XAML example shows a ResourceDictionary
named 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 this example, the ResourceDictionary
contains a single resource, which is an object of type DataTemplate
. MyResourceDictionary.xaml can be consumed by merging it into another resource dictionary.
By default, the linker will remove stand-alone XAML files from release builds when the linker behavior is set to link all assemblies. To ensure that stand-alone XAML files remain in a release build:
Add a custom
Preserve
attribute to the assembly containing the stand-alone XAML files. For more information, see Preserving code.Set the
Preserve
attribute at the assembly level:[assembly:Preserve(AllMembers = true)]
For more information about linking, see Linking Xamarin.iOS apps and Linking on Android.
Merged resource dictionaries
Merged resource dictionaries combine one or more ResourceDictionary
objects into another ResourceDictionary
.
Merge local resource dictionaries
A local ResourceDictionary
file can be merged into another ResourceDictionary
by creating a ResourceDictionary
object whose Source
property is set to the filename of the XAML file with the resources:
<ContentPage ...>
<ContentPage.Resources>
<!-- Add more resources here -->
<ResourceDictionary Source="MyResourceDictionary.xaml" />
<!-- Add more resources here -->
</ContentPage.Resources>
...
</ContentPage>
This syntax does not instantiate the MyResourceDictionary
class. Instead, it references the XAML file. For that reason, when setting the Source
property, a code-behind file isn't required, and the x:Class
attribute can be removed from the root tag of the MyResourceDictionary.xaml file.
Important
The Source
property can only be set from XAML.
Merge resource dictionaries from other assemblies
A ResourceDictionary
can also be merged into another ResourceDictionary
by adding it into the MergedDictionaries
property of the ResourceDictionary
. This technique allows resource dictionaries to be merged, regardless of the assembly in which they reside. Merging resource dictionaries from external assemblies requires the ResourceDictionary
to have a build action set to EmbeddedResource, to have a code-behind file, and to define the x:Class
attribute in the root tag of the file.
Warning
The ResourceDictionary
class also defines a MergedWith
property. However, this property has been deprecated and should no longer be used.
The following code example shows two resource dictionaries being added to the MergedDictionaries
collection of a page level 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:LightTheme />
<!-- Add more resource dictionaries here -->
</ResourceDictionary.MergedDictionaries>
<!-- Add more resources here -->
</ResourceDictionary>
</ContentPage.Resources>
...
</ContentPage>
In this example, a resource dictionary from the same assembly, and a resource dictionary from an external assembly, are merged into the page level resource dictionary. In addition, you can also add other ResourceDictionary
objects within the MergedDictionaries
property-element tags, and other resources outside of those tags.
Important
There can be only one MergedDictionaries
property-element tag in a ResourceDictionary
, but you can put as many ResourceDictionary
objects in there as required.
When merged ResourceDictionary
resources share identical x:Key
attribute values, Xamarin.Forms uses the following resource precedence:
- The resources local to the resource dictionary.
- The resources contained in the resource dictionaries that were merged via the
MergedDictionaries
collection, in the reverse order they are listed in theMergedDictionaries
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.
Related links
- XAML Markup Extensions
- Xamarin.Forms Styles
- Linking Xamarin.iOS apps
- Linking on Android
- ResourceDictionary API