I have a BaseSkin and multiple UserSkins in a separate dll from my WPF application.
Depending on who is using the application, the base skin and one of the user skins will be merged into a resource dictionary and loaded for the application to use.
What I'm aiming for is the ability to specify a style in a BaseSkin file, and then on a specific UserSkin file be able to override it, changing any properties I need to.
I know I can accomplish this by using the BasedOn attribute like this:
<Style x:Key="ButtonBg" TargetType="{x:Type Button}">
<Setter Property="Background" Value="Green"/>
</Style>
<Style x:Key="CustomButtonBg" TargetType="{x:Type Button}" BasedOn="{StaticResource ButtonBg}">
<Setter Property="Background" Value="Blue"/>
</Style>
The problem is that now the elements have to have a Style of CustomButtonBg which may not actually be implemented. Is there any way to have both styles use the same key (ButtonBg), and when they're merged have the application look for a style named ButtonBg in User first, and if one doesn't exist, use the one in base?
I was thinking that if I could give the assembly name in the BasedOn attribute to point towards the BaseSkin file, I could avoid naming errors when I give them the same key, but I can't find any way to do that. The other options are to just force an implementation of each style even if nothing gets changed, or check programatically in the skins, but those are last resorts.
You could try to take advantage of the resource lookup logic. When WPF is trying to find a resource by the key, it first look in the current element's ResourceDictionary
, then its parent's, then the parent of that, and so on.
So since you said it is conditional to the user, that could be merged in the ResourceDictionary
at the Window
level while your original base is at the Application
level.
Edit: I have better information. From MSDN on Merged Dictionaries:
Merged Dictionary Behavior
Resources in a merged dictionary occupy a location in the resource lookup scope that is just after the scope of the main resource dictionary they are merged into. Although a resource key must be unique within any individual dictionary, a key can exist multiple times in a set of merged dictionaries. In this case, the resource that is returned will come from the last dictionary found sequentially in the MergedDictionaries collection. If the MergedDictionaries collection was defined in XAML, then the order of the merged dictionaries in the collection is the order of the elements as provided in the markup. If a key is defined in the primary dictionary and also in a dictionary that was merged, then the resource that is returned will come from the primary dictionary. These scoping rules apply equally for both static resource references and dynamic resource references.
That means you can define your Base skin in a different ResourceDictionary
and merge it into another ResourceDictionary
. Have the User skin in the latter, and it will find it first, otherwise it will keep drilling down to the merged dictionary that contains Base. Each of your User dictionaries can merge the Base dictionary and you just load the User dictionary into the app instead of both separately.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With