I have a BaseSkin and multiple UserSkins in a separate dll from my WPF application.
我在WPF应用程序的单独dll中有一个BaseSkin和多个UserSkins。
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.
我的目标是能够在BaseSkin文件中指定样式,然后在特定的UserSkin文件上能够覆盖它,更改我需要的任何属性。
I know I can accomplish this by using the BasedOn attribute like this:
我知道我可以通过使用这样的BasedOn属性来实现这一点:
Base:
<Style x:Key="ButtonBg" TargetType="{x:Type Button}">
<Setter Property="Background" Value="Green"/>
</Style>
User:
<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?
问题是现在元素必须具有StyleButtonBg样式,实际上可能无法实现。是否有任何方法可以让两个样式使用相同的键(ButtonBg),当它们合并时,应用程序会在User用户中查找名为ButtonBg的样式,如果不存在,请使用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.
我想如果我可以在BasedOn属性中给出程序集名称指向BaseSkin文件,当我给它们相同的密钥时,我可以避免命名错误,但我找不到任何方法来做到这一点。其他选项只是强制执行每个样式,即使没有任何变化,或者在皮肤中以编程方式检查,但这些是最后的度假胜地。
2 个解决方案
#1
10
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.
您可以尝试利用资源查找逻辑。当WPF尝试通过键查找资源时,它首先查看当前元素的ResourceDictionary,然后查看其父元素,然后查看其父元素,依此类推。
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.
因此,既然你说它是有条件的用户,那么可以在Window级别的ResourceDictionary中合并,而你的原始基础是在应用程序级别。
Edit: I have better information. From MSDN on Merged Dictionaries:
编辑:我有更好的信息。来自合并词典的MSDN:
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.
合并字典中的资源占用资源查找范围中的位置,该位置恰好位于它们合并到的主资源字典的范围之后。虽然资源键在任何单个字典中必须是唯一的,但是在一组合并的字典中,键可以存在多次。在这种情况下,返回的资源将来自MergedDictionaries集合中按顺序找到的最后一个字典。如果在XAML中定义了MergedDictionaries集合,则集合中合并的字典的顺序是标记中提供的元素的顺序。如果在主词典中以及在合并的词典中定义了键,则返回的资源将来自主词典。这些作用域规则同样适用于静态资源引用和动态资源引用。
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.
这意味着您可以在不同的ResourceDictionary中定义Base皮肤并将其合并到另一个ResourceDictionary中。在后者中具有User皮肤,它将首先找到它,否则它将继续向下钻取到包含Base的合并字典。您的每个用户词典都可以合并Base词典,您只需将用户词典加载到应用程序中,而不是单独加载。
#2
0
You might just name your Base as BaseButtonBg and when you don't merge a user based ResourceDictionary merge a generic one containing:
您可能只将Base命名为BaseButtonBg,当您不合并基于用户的ResourceDictionary时,合并一个包含以下内容的泛型:
<Style x:Key="ButtonBg" TargetType="{x:Type Button}" BasedOn="{StaticResource BaseButtonBg}"/>
#1
10
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.
您可以尝试利用资源查找逻辑。当WPF尝试通过键查找资源时,它首先查看当前元素的ResourceDictionary,然后查看其父元素,然后查看其父元素,依此类推。
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.
因此,既然你说它是有条件的用户,那么可以在Window级别的ResourceDictionary中合并,而你的原始基础是在应用程序级别。
Edit: I have better information. From MSDN on Merged Dictionaries:
编辑:我有更好的信息。来自合并词典的MSDN:
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.
合并字典中的资源占用资源查找范围中的位置,该位置恰好位于它们合并到的主资源字典的范围之后。虽然资源键在任何单个字典中必须是唯一的,但是在一组合并的字典中,键可以存在多次。在这种情况下,返回的资源将来自MergedDictionaries集合中按顺序找到的最后一个字典。如果在XAML中定义了MergedDictionaries集合,则集合中合并的字典的顺序是标记中提供的元素的顺序。如果在主词典中以及在合并的词典中定义了键,则返回的资源将来自主词典。这些作用域规则同样适用于静态资源引用和动态资源引用。
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.
这意味着您可以在不同的ResourceDictionary中定义Base皮肤并将其合并到另一个ResourceDictionary中。在后者中具有User皮肤,它将首先找到它,否则它将继续向下钻取到包含Base的合并字典。您的每个用户词典都可以合并Base词典,您只需将用户词典加载到应用程序中,而不是单独加载。
#2
0
You might just name your Base as BaseButtonBg and when you don't merge a user based ResourceDictionary merge a generic one containing:
您可能只将Base命名为BaseButtonBg,当您不合并基于用户的ResourceDictionary时,合并一个包含以下内容的泛型:
<Style x:Key="ButtonBg" TargetType="{x:Type Button}" BasedOn="{StaticResource BaseButtonBg}"/>