In the last post, I showed how to load a complete view dynamically, but that’s not the most common way to change the visualization of data. Most of the time, you will want to just change the appearance of the view, customizing the style for a client.
If we want to apply the styles for all controls, we must use a Theme. A Theme provides the default appearance for all controls of an application. The default theme is provided by the OS the app is running, but that can be changed by using an alternate theme file, a resource dictionary that has default styles for all controls.
Loading a theme dynamically
One way to load themes dynamically is to use any theme dll available for our use (many of them are free). We can add the themes to our project using Nuget and then change the theme as we want, but that’s not the focus, here. We want to load the themes from loose XAML files dynamically.
For that, I used an open source project, named WpfThemes (https://wpfthemes.codeplex.com/), that has several themes available and creates a themes dll that can be used in our project. As it is open source, I won’t use the dll, but I will use the theme structure and its demo to show how to load the theme from its files.
I downloaded the project and restructured it in this way:
- I created a single project, LoadThemes, and added the content of the demo main window to the new project’s main window
- I created a new folder on the project, named Themes and added all themes folders from the WPF.Themes project
- I set all Theme.xaml file Build Action to None and Copy to output Directory to “Copy if newer”
With this structure, we can load all available theme names to the theme combobox using this code:
I just enumerate all folders under the Themes folder and get the folder names, removing the initial “Themes\”. Now, we must load the theme dynamically. This is done in the SelectionChanged event for the theme combobox:
The program gets the selected item and opens the Theme.xaml located in the selected folder. Then, it loads the file as a ResourceDictionary and sets the MergedDictionaries for the current Application to it. This is everything that’s needed to change the style of all controls at once.
Loading styles dynamically
Usually, you do not want such a radical change, like the theme change, but you want to change the way some controls are drawn (colors, margins, etc). For that, you just need to change some styles. One way to do it is to apply some styles to your controls and then load the resource dictionaries dynamically. For example, the project from previous post could be redesigned by using styles. We can take the Master/Detail file and apply styles to the file, setting something like this:
We can create a default resource dictionary and call it DefaultDict.xaml:
And add this dictionary to App.xaml:
When we run the application, the default style is applied to the view:
Now, we want to apply dynamic styles to the view, so we can create loose files with new resource dictionaries. In the project, create a new folder and name it Styles. In this folders, add three files and name them as Blue.xaml, Red.xaml and Yellow.xaml:
And set their Build Action to None and Copy to output directory to “Copy if newer”. As you can see, these files are very similar to the default dictionary: they override some colors and styles and add a new one, setting the font for all TextBlocks. Then, add a new Combobox in the main window, to select the new styles:
The SelectionChanged event handler for this box is:
To load the styles, we will use the LoadStyles function, called in the constructor:
When you run the program and try to change the styles, you will see a strange thing:
The font, which was not defined in the default style is changed, but the colors have not changed. This happens because we have set the styles as Static, using StaticResource when we applied the styles. In order for the style be applied dynamically, we must apply it using DynamicResource. When we change all StaticResource to DynamicResource in the master/detail file, we get this:
All the colors and styles have changed.
Conclusions
As you can see, WPF gives you a great flexibility to change you views dynamically. You can change the entire view, restyle all controls or only change the style of part of the controls. Everything can be done at runtime, and you can load the files from anywhere you want: loose files in a selected folder, from a database or from a request to a server, you can load the XAML as a string, parse and load it into your program. The files for this project are in https://github.com/bsonnino/LoadThemes (runtime themes) and https://github.com/bsonnino/DynamicXamlViews (dynamic styles).