在资源字典中扩展/覆盖样式

8
我有一个BaseSkin和多个UserSkins,它们存储在我的WPF应用程序的一个独立dll中。
根据使用应用程序的人员不同,基础皮肤和其中一个用户皮肤将合并到资源字典中,并加载供应用程序使用。
我想要的是能够在BaseSkin文件中指定样式,然后在特定的UserSkin文件中覆盖它,改变任何需要的属性。
我知道可以通过像这样使用BasedOn属性来实现这一点:
<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>

问题在于现在元素必须具有CustomButtonBg样式,但实际上可能没有实现。有没有办法让这两种样式使用相同的键(ButtonBg),并且在它们合并时,应用程序首先查找名为User中的ButtonBg样式,如果不存在,则使用base中的样式?
我想,如果我可以在BasedOn属性中给出BaseSkin文件的程序集名称,我就可以避免命名错误,当我给它们相同的键时,但我找不到任何方法来做到这一点。其他选项是强制实现每个样式,即使没有任何更改,或者在皮肤中进行程序检查,但这些都是最后的手段。
2个回答

11

你可以尝试利用资源查找逻辑。当WPF尝试按键查找资源时,首先查找当前元素的ResourceDictionary,然后是其父元素的,再然后是父元素的父元素,依此类推。

因此,既然你说这是有条件的用户问题,那么可以将其合并到Window级别的ResourceDictionary中,而原始基础则在Application级别。

编辑:我有更好的信息。来自MSDN关于合并字典的说明

合并字典行为

合并字典中的资源占据了资源查找范围中的一个位置,该位置位于它们合并到的主要资源字典的范围之后。虽然资源键必须在任何单个字典中唯一,但在一组合并的字典中可以存在多次。在这种情况下,返回的资源将来自于在MergedDictionaries集合中顺序最后发现的字典。如果MergedDictionaries集合在XAML中定义,则集合中合并的字典的顺序是提供的标记中的元素顺序。如果一个键在主字典和合并的字典中都定义了,那么将返回从主字典获取的资源。这些作用域规则对于静态资源引用和动态资源引用同样适用。

这意味着你可以在不同的ResourceDictionary中定义基础皮肤并将其合并到另一个ResourceDictionary中。将用户皮肤放入后者中,它会首先找到它,否则它将继续向下查找包含基础皮肤的合并字典。每个用户字典都可以合并基础字典,然后只需将用户字典加载到应用程序中,而不是分别加载两个字典。


如果我在窗口层面上合并它,那么每次都需要合并吗? - Brandon
可能将一块代码复制并粘贴到每个窗口中会很麻烦。也许有一种方法可以在 App 和 Window 之间或者更高层次上插入代码块。你甚至可以考虑创建一个能够抓取并用一行代码将它们插入到窗口的 ResourceDictionary 中的工具,这样你就仍然只需要一个源文件。我只是不太确定如何做出明确的建议,只是有了一个想法。 - Joel B Fant
我还没有尝试过这个,但它看起来应该可以工作。感谢您的帮助。 - Brandon

0
你可以将你的基础命名为BaseButtonBg,当你不合并基于用户的ResourceDictionary时,合并一个包含以下内容的通用资源字典:
<Style x:Key="ButtonBg" TargetType="{x:Type Button}" BasedOn="{StaticResource BaseButtonBg}"/>

实际上,我总是合并基于用户的RD,但不能保证ButtonBg的实现。这样做是可行的,但正如我在问题的结尾所说的那样,我不确定是否要强制他们指定一个空白样式。 - Brandon

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接