Merging resources

If we have a large application and our application resources are becoming overcrowded, we have the option of splitting our default colors, brushes, styles, templates, and other resources into different files. In addition to organizational and maintenance benefits, this also enables our main resource files to be shared amongst our other applications, and so this promotes reusability too.

In order to do this, we first need one or more additional resource files. We can add an additional resource file using Visual Studio, by right-clicking on the relevant project and selecting the Add option and then the Resource Dictionary... option. Upon executing this command, we will be provided with a file like this:

<ResourceDictionary  
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">   
</ResourceDictionary> 

This is one of the occasions when we do need to explicitly declare the ResourceDictionary element. Once we have transferred our styles or other resources to this file, we can merge it into our main application resources file like this:

<Application.Resources> 
  <ResourceDictionary> 
    <!-- Add Resources here... --> 
    <ResourceDictionary.MergedDictionaries> 
      <ResourceDictionary Source="Default Styles.xaml" /> 
      <ResourceDictionary Source="Default Templates.xaml" /> 
    </ResourceDictionary.MergedDictionaries> 
    <!-- ... or add resources here, but not in both locations --> 
  </ResourceDictionary> 
</Application.Resources> 

Note that we do not specify the x:Key directive for this resource dictionary. In fact, if we did specify this value on the dictionary, we would receive a compilation error:

The "Key" attribute can only be used on an element that is contained in "IDictionary".

Note also that we can set the ResourceDictionary.MergedDictionaries value either above or below our locally declared resources, but not anywhere in the middle of them. Within this property, we can declare another ResourceDictionary element for each external resource file that we want to merge and specify its location using a Uniform Resource Identifier (URI) in the Source property.

 

If our external resource files reside in our startup project with our App.xaml file, we can reference them with relative paths, as shown in the preceding example. Otherwise, we will need to use the Pack URI notation. To reference a resource file from a referenced assembly, we would need to use the following format:

pack://application:,,,/ReferencedAssembly;component/ResourceFile.xaml 

In our case, assuming that we had some resource files in a folder named Styles in a separate project, or other referenced assembly, we would merge the file using the following path:

<ResourceDictionary 
  Source="pack://application:,,,/CompanyName.ApplicationName.Resources;
  component/Styles/Control Styles.xaml" />

When merging resource files, it is important to understand how naming conflicts will be resolved. Although the x:Key directives that we set on our resources must each be unique within their declared resource dictionary, it is perfectly legal to have duplicated key values within separate resource files. As such, there is an order of priority that will be followed in these cases. Let's see an example.

Imagine that we have the aforementioned referenced resource file in a separate project and in that file, we have this resource:

<SolidColorBrush x:Key="Brush" Color="Red" /> 

Note that we would need to add a reference to the System.Xaml assembly in that project in order to avoid errors. Now imagine that we also have the locally declared Default Styles.xaml resource file that was referenced in the previous example and in that file, we have this resource:

<SolidColorBrush x:Key="Brush" Color="Blue" /> 

Let's add a Default Styles 2.xaml resource file with this resource in it:

<SolidColorBrush x:Key="Brush" Color="Orange" /> 

Now, let's say that we merge all of these resource files and add this additional resource in our application resource file:

<Application.Resources> 
  <ResourceDictionary> 
    <ResourceDictionary.MergedDictionaries> 
      <ResourceDictionary Source="Default Styles.xaml" /> 
      <ResourceDictionary Source="Default Styles 2.xaml" /> 
      <ResourceDictionary Source="pack://application:,,,/ 
        CompanyName.ApplicationName.Resources; 
        component/Styles/Control Styles.xaml" /> 
    </ResourceDictionary.MergedDictionaries> 
    <SolidColorBrush x:Key="Brush" Color="Green" /> 
    ... 
  </ResourceDictionary> 
</Application.Resources> 

Finally, let's imagine that we have this in the XAML of one of our Views:

<Button Content="Go"> 
  <Button.Resources> 
    <SolidColorBrush x:Key="Brush" Color="Cyan" /> 
  </Button.Resources> 
  <Button.Style> 
    <Style TargetType="{x:Type Button}"> 
      <Setter Property="Foreground" Value="{StaticResource Brush}" /> 
    </Style> 
  </Button.Style> 
 </Button> 

Also, let's assume that we have this in the local resources of that file:

<UserControl.Resources> 
  <SolidColorBrush x:Key="Brush" Color="Purple" /> 
</UserControl.Resources> 

When running the application, our button text will be cyan, because the main rule of resource scope is that the highest priority resource that will be used will always be the most locally declared resource. If we removed or commented out the local brush declaration, the button text would then become purple when the application was next run.

If we removed the local purple brush resource from the control's Resources section, the application resources would be searched next in an attempt to resolve the Brush resource key. The next general rule is that the latest declared resource will be resolved. In this way, the button text would then become green, because of the locally declared resource in the App.xaml file, which would override the values from the merged dictionaries.

However, if this green brush resource was removed, an interesting thing would happen. Given the recently stated rules, we might expect that the button text would then be set to red by the Control Styles.xaml resource file from the referenced assembly. Instead, it will be set to orange by the resource in the Default Styles 2.xaml file.

 

This is the result of a combination of the two rules together. The two locally declared resource files have a higher priority than the resource file from the referenced assembly because they have been declared more locally than it. The second of the two locally declared resource files takes precedence over the first because it was declared after the first.

If we removed the reference to the second of the locally declared resource files, the text would then be set to blue by the resource in the Default Styles.xaml file. If we then removed the reference to this file, we would finally see the red button text that would be set by the Control Styles.xaml file from the referenced assembly.