I'm trying to set up my styles properly. Thus I've created an external ResourceDictionary
for all common style attributes, in which I've defined a default font family like this:
<FontFamily x:Key="Default.FontFamily">Impact</FontFamily>
This way the family changes at all places when I change this single line.
using and referencing StaticResource
Now I want to use this default font family wherever nothing else is defined, which is in most places (but not all). However, I want to retain the ability of defining other font families for any place this is used. So I went with the examples I've found here and here, and defined the default font explicitly for a group box header:
<StaticResource x:Key="GroupBox.HeaderFontFamily" ResourceKey="Default.FontFamily"/>
I use this on a TextBlock
that is included in a template of my group box.
<Style x:Key="GroupBoxHeaderTextStyle" TargetType="{x:Type TextBlock}">
<Setter Property="FontFamily" Value="{StaticResource GroupBox.HeaderFontFamily}"/>
</Style>
So far, this is working. However, as soon as I add another line:
<StaticResource x:Key="GroupBox.HeaderFontFamily" ResourceKey="Default.FontFamily"/>
<StaticResource x:Key="FormLabel.FontFamily" ResourceKey="Default.FontFamily"/>
I get this exception thrown:
Exception: Cannot find resource named 'Hsetu.GroupBox.HeaderFontFamily'. Resource names are case sensitive.
So I've experienced that WPF cannot find an Element directly addressed when followed by a StaticResource
(Yes, this also counts for elements other than StaticResources. eg, if I tried to address the font family "Default.FontFamily"
directly I would get the same error, because it precedes a StaticResource
element)
using DynamicResource and referencing StaticResource
I've tried using a DynamicResource
as suggested in the 2nd example I've provided a link to above:
<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>
This throws the following error:
ArgumentException: 'System.Windows.ResourceReferenceExpression' is not a valid value for property 'FontFamily'.
using and referencing DynamicResource
Using DynamicResource
in my group box style only changed the error message:
<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: 'Unable to cast object of type 'System.Windows.ResourceReferenceExpression' to type 'System.Windows.Media.FontFamily'.'
adding a dummy element
So, as this problem only occurs when my StaticResource
is followed by another, I've got the idea of including a dummy element between the resources.
<StaticResource x:Key="GroupBox.HeaderFontFamily" ResourceKey="Default.FontFamily"/>
<Separator x:Key="Dummy"/>
<StaticResource x:Key="FormLabel.FontFamily" ResourceKey="Default.FontFamily"/>
Now, this works. Hooray! But wait a minute... continuing on, I tried to use the second resource "FormLabel.FontFamily"
<Style x:Key="FormLabelStyle" TargetType="{x:Type Label}">
<Setter Property="FontFamily" Value="{StaticResource FormLabel.FontFamily}"/>
</Style>
This throws another exception now:
System.InvalidCastException: 'Unable to cast object of type 'System.Windows.Controls.Separator' to type 'System.Windows.Media.FontFamily'.'
Bug?
I'm not even using the Separator
at all, so what is going on? I assume, when addressing a StaticResource, WPF actually tries to use the preceding element - which only worked in the beginning because the preceding element was a FontFamily
by chance - and not the element that is referenced with the ResourceKey
. At the same time, rendering the preceding element inaccessible directly. In order to confirm my suspicion, I've replaced the Separator
with another FontFamily
.
<StaticResource x:Key="GroupBox.HeaderFontFamily" ResourceKey="Default.FontFamily"/>
<FontFamily x:Key="Dummy">Courier New</FontFamily>
<StaticResource x:Key="FormLabel.FontFamily" ResourceKey="Default.FontFamily"/>
And indeed, it worked, but the Labels are now using the Courier New font instead of the referenced Impact font.
Btw. this does not only happen with font families but also other attributes (FontSize
, BorderThickness
, FontWeight
, etc.). So, is this actually a bug in WPF or are StaticResource
s supposed to act like this (which wouldn't make any sense to me)? How can I get to use my font family in multiple places only defining it once?