Load Resource Dictionaries at Runtime in WPF

One of the really cool features of WPF is the ability to style controls. Styles in WPF can be grouped together into Resource Dictionaries. These resource dictionaries can then be loaded dynamically at runtime with just a small amount of Visual Basic or C# code. In Figure 1 you see an example WPF form that allows you to type in a XAML file name that contains a resource dictionary. The styles within this resource dictionary are applied to a Grid control. In this case, it is just a simple gradient fill, but the same concept will apply even if you had styles for all controls in your application.

Load Resource 
Figure 1: Loading resources on the fly allows you to change styles at runtime

The Resource Dictionaries

A resource dictionary is nothing more than a collection of styles grouped together under a <ResourceDictionary> xaml tag. Each style can be keyed, or have just a TargetType attribute. The samples in this article are very simple and just have one Style that applies to a Grid control. The style will set the Background property of a Grid to a LinearGradientBrush of a certain set of colors. Below is the Green.xaml file.

<ResourceDictionary
 xmlns=http://schemas.microsoft.com/winfx/2006/xaml/presentation
 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
  <Style TargetType="Grid"
         x:Key="DynamicGridBrush">
    <Setter Property="Background">
      <Setter.Value>
        <LinearGradientBrush StartPoint="0,0"
                             EndPoint="0,1">
          <GradientStop Offset="0"
                        Color="LightBlue" />
          <GradientStop Offset="0.65"
                        Color="LightGreen" />
          <GradientStop Offset="1"
                        Color="White" />
        </LinearGradientBrush>
      </Setter.Value>     
    </Setter>
  </Style>
</ResourceDictionary>

Next, is the Blue.xaml resource dictionary.

<ResourceDictionary
 xmlns=http://schemas.microsoft.com/winfx/2006/xaml/presentation
 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
  <Style TargetType="Grid"
         x:Key="DynamicGridBrush">
    <Setter Property="Background">
      <Setter.Value>
        <LinearGradientBrush StartPoint="0,0"
                             EndPoint="0,1">
          <GradientStop Offset="0"
                        Color="Blue" />
          <GradientStop Offset="0.65"
                        Color="LightBlue" />
          <GradientStop Offset="1"
                        Color="AliceBlue" />
        </LinearGradientBrush>
      </Setter.Value>     
    </Setter>
  </Style>
</ResourceDictionary>

Now that you have the resource dictionaries defined you will now want to switch between them dynamically at runtime.

Setting the Style

In the form shown in Figure 1 you see a grid with a linear gradient. This is accomplished using the following code:

<Grid Style="{DynamicResource DynamicGridBrush}"
      Height="180"
      Width="250" />

Notice the use of the {DynamicResource DynamicGridBrush}. This code allows your XAML code to compile even if it can’t find the “DynamicGridBrush” at compile-time. The DynamicResource keyword says to look for this resource, but if you can’t find that resource, then just do not set the Style at this time. If after loading a new resource dictionary the style becomes available, then go ahead and apply the style.

Loading a Resource

To load a XAML file from disk, you will first need to open that file as a file stream. Next you can use the XamlReader class from the System.Windows.Markup namespace to load that file stream and cast it into a ResourceDictionary. You can then clear any old dictionaries that were previously loaded. Next you add to the MergedDictionaries collection of the current Window’s Resources property the dictionary you just loaded from disk.

C#
private void DynamicLoadStyles()
{
  string fileName;

  fileName = Environment.CurrentDirectory() +
               @"\Dictionaries\" + txtXamlName.Text;

  if (File.Exists(fileName))
  {
    using (FileStream fs = new FileStream(fileName, FileMode.Open))
    {
      // Read in ResourceDictionary File
      ResourceDictionary dic =
         (ResourceDictionary)XamlReader.Load(fs);
      // Clear any previous dictionaries loaded
      Resources.MergedDictionaries.Clear();
      // Add in newly loaded Resource Dictionary
      Resources.MergedDictionaries.Add(dic);
    }
  }
  else
    MessageBox.Show("File: " + txtXamlName.Text +
       " does not exist. Please re-enter the name.");
}

VB.NET
Private Sub DynamicLoadStyles()
  Dim fileName As String
  Dim dic As ResourceDictionary = Nothing

  fileName = Environment.CurrentDirectory & _
    "\Dictionaries\" & txtXamlName.Text

  If File.Exists(fileName) Then
    Using fs As FileStream = New FileStream(fileName, _
         FileMode.Open)
      ' Read in ResourceDictionary File
      dic = CType(XamlReader.Load(fs), ResourceDictionary)
      ' Clear any previous dictionaries loaded
      Resources.MergedDictionaries.Clear()
      ' Add in newly loaded Resource Dictionary
      Resources.MergedDictionaries.Add(dic)
    End Using
  Else
    MessageBox.Show("File: " + fileName + _
                    " does not exist. Please re-enter.")
  End If
End Sub

To ensure that you can access the Green.xaml and the Blue.xaml files you need to add each of them to your Visual Studio solution in a folder called \Dictionaries. Next you need to click on each of these files in turn and bring up the Properties Window. Change the Build Action to “Content” and the Copy to Output Directory to “Copy Always”. This ensures that the Environment.CurrentDirectory plus the directory plus the file name will find the appropriate file at runtime.

Summary

Having the ability to load resource dictionaries at runtime can aid you a lot in changing the look and feel of a WPF application. You can have a set of styles that a user is allowed to choose from. You could then store their choice in a user table, and load that value when the application starts up. This allows you to customize each user’s experience with your application. You can control color, font size and many other attributes about a user’s experience with your user interface.

NOTE: You can download the complete sample code at my website. http://www.pdsa.com/downloads. Choose Tips & Tricks, then "WPF: Dynamically Load Resources" from the drop-down.

Good Luck With Your Coding,
Paul Sheriff

** SPECIAL OFFER FOR MY BLOG READERS **
Visit http://www.pdsa.com/Event/Blog for a free eBook on "Fundamentals of N-Tier".

Past Blog Content

Blog Archive

3 Comments

  • It would probably be a good idea to wrap the MergedDictionaries.Clear and MergedDictionaries.Add calls in a BeginInit/EndInit block:

    Resources.BeginInit()
    Try
    Resources.MergedDictionaries.Clear()
    Resources.MergedDictionaries.Add(dic)
    Finally
    Resources.EndInit()
    End Try

    If you don't, your application will try to update all dynamic resources after both calls. If you look at the output window in Visual Studio, you'll see that this results in a lot of "resource not found" exceptions.

  • hi,
    i used it, by breakpoint checked that resource file is successfully loaded but my application sytles didn't changed as defined in the dictionary file
    how do it do that?

  • Saboor,

    I don't know. Did you run my sample and it worked? You are using WPF 3.5 correct?

    Paul

Comments have been disabled for this content.