我正在尝试正确设置我的样式。因此,我创建了一个外部的ResourceDictionary
用于所有常见的样式属性,在其中我定义了默认字体系列,如下所示:
<FontFamily x:Key="Default.FontFamily">Impact</FontFamily>
当我更改这一行时,家族中的所有地方都会发生变化。
使用和引用StaticResource
现在,我想在任何没有定义其他字体族的地方都使用这个默认字体族,大多数情况下是这样(但不是所有情况)。然而,我希望保留在任何使用此字体族的地方定义其他字体族的能力。因此,我采用了我在这里和这里找到的示例,并为一个组框标题明确定义了默认字体。
<StaticResource x:Key="GroupBox.HeaderFontFamily" ResourceKey="Default.FontFamily"/>
我将用于我的GroupBox模板中包含的TextBlock上。
<Style x:Key="GroupBoxHeaderTextStyle" TargetType="{x:Type TextBlock}">
<Setter Property="FontFamily" Value="{StaticResource GroupBox.HeaderFontFamily}"/>
</Style>
到目前为止,这个是有效的。但是,一旦我添加另一行:
<StaticResource x:Key="GroupBox.HeaderFontFamily" ResourceKey="Default.FontFamily"/>
<StaticResource x:Key="FormLabel.FontFamily" ResourceKey="Default.FontFamily"/>
我遇到了以下异常:
异常:找不到名为“Hsetu.GroupBox.HeaderFontFamily”的资源。资源名称区分大小写。
所以我发现当使用StaticResource
直接寻址一个元素时,WPF无法找到它(是的,这也适用于其他元素,例如,如果我尝试直接寻址字体族"Default.FontFamily"
,我会得到相同的错误,因为它在StaticResource
元素之前)
使用DynamicResource并引用StaticResource
我尝试了上面提供链接中第二个示例中建议的使用DynamicResource
:
<DynamicResource x:Key="GroupBox.HeaderFontFamily" ResourceKey="Default.FontFamily"/>
<DynamicResource x:Key="FormLabel.FontFamily" ResourceKey="Default.FontFamily"/>
<Style x:Key="GroupBoxHeaderTextStyle" TargetType="{x:Type TextBlock}">
<Setter Property="FontFamily" Value="{StaticResource GroupBox.HeaderFontFamily}"/>
</Style>
这会抛出以下错误:
ArgumentException: “System.Windows.ResourceReferenceExpression” 不是属性“FontFamily”的有效值。
使用和引用 DynamicResource
在我的分组框样式中使用 DynamicResource
只会更改错误消息:
<DynamicResource x:Key="GroupBox.HeaderFontFamily" ResourceKey="Default.FontFamily"/>
<DynamicResource x:Key="FormLabel.FontFamily" ResourceKey="Default.FontFamily"/>
<Style x:Key="GroupBoxHeaderTextStyle" TargetType="{x:Type TextBlock}">
<Setter Property="FontFamily" Value="{DynamicResource GroupBox.HeaderFontFamily}"/>
</Style>
System.InvalidCastException: '无法将类型为 'System.Windows.ResourceReferenceExpression' 的对象强制转换为类型 'System.Windows.Media.FontFamily'。'
添加虚拟元素
因此,由于这个问题只在我的StaticResource
后面跟着另一个资源时才会出现,我想到了在资源之间包含一个虚拟元素的方法。
<StaticResource x:Key="GroupBox.HeaderFontFamily" ResourceKey="Default.FontFamily"/>
<Separator x:Key="Dummy"/>
<StaticResource x:Key="FormLabel.FontFamily" ResourceKey="Default.FontFamily"/>
现在,这个可以工作了。万岁!但是等一下……继续进行,我尝试使用第二个资源"FormLabel.FontFamily"
<Style x:Key="FormLabelStyle" TargetType="{x:Type Label}">
<Setter Property="FontFamily" Value="{StaticResource FormLabel.FontFamily}"/>
</Style>
现在会抛出另一个异常:
System.InvalidCastException:“无法将类型为'System.Windows.Controls.Separator'的对象转换为类型'System.Windows.Media.FontFamily'。”
有 Bug 吗?
我根本没有使用 Separator
,那么到底发生了什么?我猜想,在引用静态资源时,WPF 实际上会尝试使用前面的元素 - 一开始只是因为前面的元素恰好是 FontFamily
才能正常工作,并不是使用 ResourceKey
引用的元素。同时,前面的元素也无法直接访问。为了确认我的猜想,我已经用另一个 FontFamily
替换了 Separator
。
<StaticResource x:Key="GroupBox.HeaderFontFamily" ResourceKey="Default.FontFamily"/>
<FontFamily x:Key="Dummy">Courier New</FontFamily>
<StaticResource x:Key="FormLabel.FontFamily" ResourceKey="Default.FontFamily"/>
确实,这个方法可以解决问题,但是标签现在使用 Courier New 字体而不是 Impact 字体。
顺便说一下,这种情况不仅发生在字体族中,还发生在其他属性(FontSize
、BorderThickness
、FontWeight
等)中。那么,这到底是 WPF 中的 bug 还是 StaticResource
应该像这样工作(这对我来说毫无意义)?如何在只定义一次的情况下在多个位置使用我的字体族?
object value = target.FindResource(resourceKey);
之后直接调用了try-catch块。现在加载时间恢复正常。感谢您的帮助。 - Otto Abnormalverbraucherobject value = target.FindResource(resourceKey);
中找不到“FormLabel.FontFamily”。 - Otto Abnormalverbraucher