当某些需要皮肤修改的项目不支持 DynamicResourceExtention 类型的值时,启用 WPF 应用程序动态皮肤的最佳方法是什么?特别是,我们的问题是 ConverterParameters 需要 StaticResourceExtentions。
这是我们使用 Visual Studio 2008 和 WPF 3.5 使用 ConverterParameters 的情况。
我们有一个自定义转换器,它接受一个值和一个参数并简单地返回他们的产品。非常简单,工作正常,我们将它用于各种任务,包括设置一些窗口元素大小。例如,传递“Source={x:Static SystemParameters.PrimaryScreenHeight}”的值和“0.1”的参数使我们能够将元素的高度设置为屏幕高度的 1/10。
Height="{Binding Source={x:Static SystemParameters.PrimaryScreenHeight},
Converter={StaticResource PctConverter},
ConverterParameter=0.1}"
其中 PctConverter 是对我们自定义转换器的资源引用。那里没问题。
现在我们想通过提取 ConverterParameter 并将其放入单独的资源中动态地为应用程序设置皮肤。例如,我们可能希望元素高度在某些皮肤中为屏幕高度的 0.1,而在其他皮肤中为屏幕高度的 0.25。最初我们认为我们只需将 ConverterParameter 设置为 DynamicResource,但这不支持,因此我们必须使用 StaticResourceExtension 设置它,如下所示:
Height="{Binding Source={x:Static SystemParameters.PrimaryScreenHeight},
Converter={StaticResource PctConverter},
ConverterParameter={StaticResource OurElementHeightParameter}}"
其中 OurElementHeightParameter 在单独的 ResourceDictionary(称为 MainResource.xaml)中定义如下:
<sys:Double x:Key="OurElementHeightParameter">0.1</sys:Double>
(其中命名空间定义为 xmlns:sys="clr-namespace:System;assembly=mscorlib"。)
就提取 CustomParameter 而言,这很好用,但它仍然无法让我们通过动态交换皮肤来更改 ConverterParameter。
在对此进行了更多研究之后,特别是以下文章
我们认为我们现在需要做的是获取我们的 StaticResourceExtention 并使用资源别名在幕后动态设置它的值。
为了做到这一点,我们将之前的 OurElementHeightParameter 资源替换为以下两个资源
<sys:Double x:Key="SkinnedHeightRatio">0.1</sys:Double>
<StaticResourceExtension x:Key="OurElementHeightParameter" ResourceKey="SkinnedHeightRatio" />
效果很好,产生了相同的结果。
当一切正常时,我们认为将 SkinnedHeightRatio 资源放置在单独的 ResourceDictionary(称为 Skin.xaml)中并将其与原始 MainResource.xaml ResourceDictionary 合并是一件简单的事情,我们将拥有我们所追求的动态皮肤。
但是,一旦我们提取<sys:Single x:Key="SkinnedHeightRatio">0.1</sys:Single>
到另一个 ResourceDictionary,我们就会遇到如下构建错误:
未知的构建错误,“索引超出范围。必须是非负数且小于集合的大小。
更奇怪的是,如果我们将上面的两个资源保存在同一个 ResourceDictionary 中,并通过在它们之间放置另一个随机资源来分隔它们,例如
<sys:Double x:Key="SkinnedHeightRatio">0.1</sys:Double>
<Thickness x:Key="SomeRandomResource" >5</Thickness>
<StaticResourceExtension x:Key="OurElementHeightParameter" ResourceKey="SkinnedHeightRatio" />
然后 OurElementHeightParameter 指向其正上方的 SomeRandomResource,而不是其 ResourceKey 属性 (SkinnedHeightRatio) 中指定的资源,后者仅在其上方 2 行...在这种情况下,传递给转换器的参数是厚度 SomeRandomResource。
一切都非常混乱,让我们认为我们完全找错了树。那么我们哪里错了?
如果有人需要重现该问题的应用程序的完整代码,我可以将其发布。
任何指针都非常感谢。