views:

482

answers:

2

Scenario:

I want to use 3 standard font size for my WPF application : BigFontSize, NormalFontSize, and SmallFontSize. These are double values and they are defined in resource dictionary as (where sys is appropriately defined):

<sys:Double x:Key="BigFontSize">18</sys:Double>
<sys:Double x:Key="NormalFontSize">14</sys:Double>
<sys:Double x:Key="SmallFontSize">12</sys:Double>

This works well. But i have randomly selected 14 as a normal size. What i want is to get a system defined font size for NormalFontSize. (If that's done, I can use a converter as described here to get BigFontSize and SmallFontSize relative to NormalFontSize)


Clue :

I found from the documentation that default font size is stored in a static property (double) SystemFonts.MessageFontSize. But what should I do to retrieve that value to resource dictionary? (I know Binding or DynamicResource cannot be applied. But hey, this is a static value, so how can I apply StaticResource or x:Static or whatever?)

I have tried

<sys:Double x:Key="XXXFontSize">
    <StaticResource ResourceKey="SystemFonts.MessageFontSize" />
</sys:Double>

and

<sys:Double x:Key="XXXFontSize">
    <x:Static ResourceKey="SystemFonts.MessageFontSize" />
</sys:Double>

Both of which doesn't seem to work (as expected). I get an error saying Cannot add content to object of type 'System.Double'.

Note:

  • I don't want to do this from code, e.g from App(). (Is it possible to have a code-behind for ResourceDictionary?)
  • I don't want to encapsulate this in generalized style from which other styles can be derived (using BasedOn) because I have several Resource Dictionaries, and it'll not be possible to use DynamicResource with BasedOn
    That is, I cannot use

    <Style x:Key="BigFont" TargetType="{x:Type Control}"}>
        <Setter Property="Control.FontSize" 
                Value="{Binding Source={x:Static SystemFonts.MessageFontSize},
                                Converter={ . . . }" />
    </Style>
    

    Because, if I have a style in other ResourceDictionary, say HeaderTextBlockStyle, then I would have to use BasedOn={DynamicResource BigFont} which is not possible (I think)

Any help would be greatly appreciated.
Thank you.

TAGS : WPF SystemFonts.MessageFontSize ResourceDictionary FontSize BasedOn DynamicResource

A: 

Check out this article: Override default styles It may have what you are looking for.

Joshua Cauble
Thanks Joshua, for your quick reply! The article is interesting, but it doesn't exactly address my problem. I know we can "override" the default style, but what I want is to keep the default `FontSize` and store it into a resource (of type `double`) so that it can be used to compute relative value of other double resources (even that seems to be my next question!)
Mihir Gokani
Hmm, well, one thing I could think of would be to change your code to use a Converter. You could then set your Control.FontSize to a converter object that is evaluated on a control by control basis. Take a look at this http://stackoverflow.com/questions/312044/wpf-pass-the-value-of-one-control-to-a-converter-to-set-the-width-on-another-coIt might provide an alternative. It's not fully in the resource but may allow you do to what you are trying to do.
Joshua Cauble
Do you mean that I should bind each control's font property to `SystemFonts.MessageFontSize` and a converter (suppose `FontSizeMapper`) that takes parameter `B`, `N`, and `S` (for Big, Normal and Small) and returns a font size accordingly? Yes, That's an option, but don't you think it'll be a bit easy if I encapsulate this in controls' style (as mentioned in my question *Note#2*) without using `BasedOn={...}` ?
Mihir Gokani
What I was thinking was more along the lines of just setting your styles FontSize property to use the convert to get the value. Of course I'm assuming that you have some global value to say I want to swtich everything to big, small, etc. and it's not just for an individual control. That way you could have a more system level variable accessed from the convert and let the converter determine what to put there. If I get a chance I'll see if I can put together a sample and post it into my original comments.
Joshua Cauble
Ok, I take it back it's not as clear as I thought it would be. The only viable option I can see is to override the default value. You could accomplish this through resource dictionaries. So have a dictionary for each size you want and then merge the correct one in. Look into switching WPF Themes / resource dictionaries at runtime to get the general idea. I think that might be the easist way for you to accomplish this.
Joshua Cauble
Yes, it's tricky, and I've started believing that it's not possible! As for now I'm not changing the code - but I'm not really happy with my-chosen numbers (18 for big etc). Anyway, thanks for your wonderful suggestions :)
Mihir Gokani
The closest I have gotten to it is to have a resource dictionary that overrides that value for each size difference you want. Then in my style for each control type set the fontsize to a dynamic resource and point to the static value. When you change your dictionaries by doing add / remove operations it will change your styling. Still requires a lot of styling work.
Joshua Cauble
I think I've got the answer, in fact the answer was in my question only! As mentioned in "Note" section "Is it possible to have a code-behind for ResourceDictionary?"... Yes.. it's really possible to have a partial class of `ResourceDictionary`. I haven't seen any examples on this anywhere, though; I've just done "trial-and-error" and it seems that it's possible. What is your opinion on this @Joshua? (I'll upload the code shortly)
Mihir Gokani
A: 

I've done like this...

public partial class GlobalResources : ResourceDictionary
{
    public GlobalResources()
    {
        this.Add("GiantFontSize", SystemFonts.MessageFontSize * 2.5);
        this.Add("BigFontSize", SystemFonts.MessageFontSize * 1.5);
        this.Add("MediumFontSize", SystemFonts.MessageFontSize * 1.25);
        this.Add("NormalFontSize", SystemFonts.MessageFontSize);
        this.Add("SmallFontSize", SystemFonts.MessageFontSize * 0.85);
    }
}

... and it's working like like a miracle!!! I can use these resources in the same (partial) resource dictionary or from other resource dictionaries like this...

<Style ...>
    <Setter Property="FontSize"
            Value="{DynamicResource MediumFontSize}" />

    ...

</Style>

I don't know if it is a "good practice" or not (please comment on this), I only know that it works..!!!

Mihir Gokani