Can WPF themes be used to include multiple skins for an application that can be changed at runtime?
Here is a snippet of code that I used in my application that supported theming. In this example, I have two themes (Default and Classic XP). The theme resources are stored in the DefaultTheme.xaml and ClassicTheme.xaml respectively.
This is the default code in my App.xaml
<Application ...> <Application.Resources> <ResourceDictionary> <ResourceDictionary.MergedDictionaries> <ResourceDictionary Source="ArtworkResources.xaml" /> <ResourceDictionary Source="DefaultTheme.xaml" /> </ResourceDictionary.MergedDictionaries> <Style x:Key="SwooshButton" TargetType="ButtonBase"> <!-- style setters --> </Style> <!-- more global styles --> </ResourceDictionary> </Application.Resources></Application>
Then in the code behind of the App.xaml I have the following method to allow for changing the theme. Basically, what you do is clear the Resource Dictionaries and then reload the dictionary with the new theme.
private Themes _currentTheme = Themes.Default; public Themes CurrentTheme { get { return _currentTheme; } set { _currentTheme = value; } } public void ChangeTheme(Themes theme) { if (theme != _currentTheme) { _currentTheme = theme; switch (theme) { default: case Themes.Default: this.Resources.MergedDictionaries.Clear(); AddResourceDictionary("ArtworkResources.xaml"); AddResourceDictionary("DefaultTheme.xaml"); break; case Themes.Classic: this.Resources.MergedDictionaries.Clear(); AddResourceDictionary("ArtworkResources.xaml"); AddResourceDictionary("ClassicTheme.xaml"); break; } } } void AddResourceDictionary(string source) { ResourceDictionary resourceDictionary = Application.LoadComponent(new Uri(source, UriKind.Relative)) as ResourceDictionary; this.Resources.MergedDictionaries.Add(resourceDictionary); }
What you'll also need to keep in mind with this approach is that any styles that utilize a theme will need to have a dynamic resource. For example:
<Window Background="{DynamicResource AppBackgroundColor}" />
I don't know of a way of doing this in the framework, but you can do it if you style every control that can change yourself.
The theory is to make the style a DynamicResource
and then load the ResourcesDictionary
based on the users configuration for the different style.
Here is an article that has an example.