I'm designing some themes for my C# / XAML application and would like to define my theme in one XAML file (ResourceDictionary
), with variations in colour in several other XAML files (ResourceDictionaries).
So, I'm attempting:
<Style TargetType="ListBox">
<Setter Property="Foreground" Value="{StaticResource ResourceKey=ForegroundBrush}" />
<Setter Property="Background" Value="{StaticResource ResourceKey=BackgroundBrush}" />
</Style>
In a generic theme XAML file which is in a class library and is not referenced from my main app. I then have a second file:
<Color x:Key="BackgroundColour" A="#FF" R="#10" G="#10" B="#40" />
<Color x:Key="BackgroundColour2" A="#FF" R="#10" G="#10" B="#FF" />
<Color x:Key="BorderColour" A="#FF" R="#00" G="#00" B="#FF" />
<Color x:Key="ForegroundColour" A="#FF" R="#FF" G="#FF" B="#FF" />
<Color x:Key="ForegroundColour2" A="#FF" R="#80" G="#80" B="#FF" />
<LinearGradientBrush x:Key="GradientForegroundBrush" EndPoint="0.5,1" StartPoint="0.5,0">
<GradientStop Color="{StaticResource ForegroundColour}" Offset="0"/>
<GradientStop Color="{StaticResource ForegroundColour2}" Offset="1"/>
</LinearGradientBrush>
I can obviously then have several of these files defining different colours on the same basic theme. I have attempted:
<ResourceDictionary Source="basestyle.xaml" x:Key="basestyle" />
I would then reference bluestyle.xaml
, redstyle.xaml
etc... from my application. This works well if I copy the entire theme across to each file, but being able to reuse the basic code seems neater.
Is there a way to do this?
If you want to separate the resources like brushes or specific styles from your theme styles and control templates, you can simply create the generic Themes\Generic.xaml
resource dictionary with references to recource keys as you did in your example with e.g. ForegroundBrush
.
Then you can create a specific style resource dictionary, e.g. redstyle.xaml
that contains all the resources with the correspondig keys. Alternatively, you could additionally create another basestyle.xaml
resource dicitonary that contains some resources shared by all conrete theme variations that you do not want to store in the theme resource dictionary either.
In order to apply a style, add the necessary resource dictionaries to the App.xaml
file as merged dictionaries. Please note, that the order matters. Include resource dictionaries that are needed by other resource dictionaries first. The lookup of StaticResource
s and DynamicResources
will find the resource with a matching key, that was added last here. For more information on that, refer to Lookup behavior for XAML resource references.
<Application x:Class="YourApplication"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<!-- Base style that includes all default resources and styles. -->
<ResourceDictionary Source="basestyle.xaml"/>
<!-- Red style that includes just specific resources and style that changed. -->
<ResourceDictionary Source="redstyle.xaml"/>
<!-- Your control theme that references the resources and styles. -->
<ResourceDictionary Source="Themes/Generic.xaml"/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
</Application>
If you intend to switch the styles at runtime, you will have to replace the corresponding dictionaries in code, e.g.:
App.xaml.cs
by modifying the Resources
dictionariesApplication.Current.Resources
.If you do not replace all dictionaries, including your generic control themes dictionary, you will have to use the DynamicResource
markup extension instead of StaticResource
, because the latter one does not pick up changes to references resources at runtime.
The StaticResource Markup Extension processes a key by looking up the value for that key in all available resource dictionaries. Processing happens during load, which is when the loading process needs to assign the property value. The DynamicResource Markup Extension instead processes a key by creating an expression, and that expression remains unevaluated until the app runs, at which time the expression is evaluated and provides a value.