How do the default color, font family and font size for a TextBlock and Label get set in an WPF app?

25,286

Solution 1

As far as I remember, in most cases classes like TextBlock, TextBox and many others take the text color from the TextElement.Foreground property. The property value is inherited throughout the visual tree, i.e. you may set it on the root element and have most of the text change its color. For example:

<Grid TextElement.Foreground="Red">
  <TextBlock Text="test"/>
</Grid>

In fact, the same is true even for labels: the setter in their default style simply sets the TextElement.Foreground to one of the system colors.

However, this is true only for the default state of controls. Altered states, like highlighting, are not inherited, but rather taken from the system colors, as Rachel has written.

UPDATE

The same is true for FontSize and FontFamily. They are properties of the TextElement class that have attached property usage. They inherit their values. Once you set a value on a visual tree item, all its children will get the same value. Unless they override it either by an explicit property assignment, or by style and so on.

Once again, text color font size and font family are governed by the value of TextElement.Foreground, TextElement.FontSize and TextElement.FontFamily attached dependency properties on a specific visual element.

Some controls, like Label explicitly set their Foreground to some brush. It happens so that the brush is one of the SystemColors. But it doesn't have to be true for all controls. Others (TextBlock, TextBox, etc.) don't override the property value and just use some default settings evaluated on startup. The same happens to FontSize and FontFamily. You do not need to set them wherever in order for them to work. That's how WPF works.

Supposedly, the values depend on the system theme. I believe they are evaluated during the app startup. Perhaps they are configurable.

UPDATE 2

Answers to your new questions:

How does a TextBlock get its default color, if the client app doesn't provide any style, either programmatically or through xaml?

It takes it from the inherited value of the TextElement.Foreground attached dependency property. By default it is inherited from the root visual element, which in turn is simply set to the default value of the dependency property (Brushes.Black). See also

How does a Label get its default color?

It takes it from the value of the TextElement.Foreground attached dependency property. Since its default style sets it to the {DynamicResource {x:Static SystemColors.ControlTextBrushKey}, it gets bound to the system color.

How does a TextBlock get its default font size and font family, if the client app doesn't provide any style, either programmatically or through xaml?

The same as for its text color. MSDN says that for the default value of the font size is SystemFonts.MessageFontSize which depends on system settings. Font family is determined in similar way from SystemFonts.MessageFontFamily. Both these default values are passed to the FrameworkPropertyMetadata constructor upon dependency property registration in the TextElement static constructor.

Going deeper: SystemFonts.MessageFontFamily and SystemFonts.MessageFontSize wrap internal SystemParameters.NonClientMetrics which in turn are retrieved from the WIN32 native SystemParametersInfo http://msdn.microsoft.com/en-us/library/ms724947. Thus the WPF is tightly integrated with all Windows UI stuff like themes, fonts, etc.

How does a Label get its default font size and font family?

The same as for TextBlock. Label derives from ContentControl which in turn derives from Control. Control class adds itself as an owner of the TextElement.FontFamily and TextElement.FontSize properties with the same default values.

See also:

Property Value Inheritance

UPDATE 3

You should understand the main idea: the values are inherited. It means they might be inherited from anywhere, from any control. You can tell exactly which one it is inherited from only for a certain logical tree structure. You change it a bit - and the colors change. Someone sets a property's value explicitly - and all children will inherit the value. Therefore your questions make little practival sense. But they are still interesting from the perspective of undestanding the WPF.

Overriding default values

Although you cannot change the values of the SystemFonts properties (they are read-only), you don't have to. To change the font size and family for the whole window, simply assign the desired values to the TextElement attached properties on the Window:

<Window TextElement.FontSize="20" TextElement.FontFamily="Century Gothic">
  ..
</Window>

and all controls that do not explicitly override the inheritance will receive the settings. For those that do override - you'll have to override their default styles or even throw them away if they hard-code the values.

The same approach works for TextElement.Foreground (and Background and so on).

Solution 2

The default colors are pulled from the operating system's settings.

You can overwrite them by creating a brush which has the a key that references a SystemColors brush key

<SolidColorBrush x:Key="{x:Static SystemColors.HighlightBrushKey}" Color="Red"/>

Solution 3

According to this: http://msdn.microsoft.com/en-us/library/ms788718.aspx

By default, WPF uses the GlobalUserInterface.composite font in your Windows\Fonts directory.

And according to this: http://msdn.microsoft.com/en-us/library/system.windows.controls.textblock.fontsize(v=vs.95).aspx

A non-negative value that specifies the font size, measured in pixels. The default is 11.

In addition, you can find many of the other default values stored in various places in the MSDN site: http://msdn.microsoft.com/en-us/library/system.windows.controls.textblock.fontstyle(v=VS.95).aspx for the style, which says:

The requested font style, which is a FontStyle that is obtained from one of the FontStyles property values. The default is Normal.

Share:
25,286
mobileTofu
Author by

mobileTofu

Updated on July 09, 2022

Comments

  • mobileTofu
    mobileTofu almost 2 years

    Edit: I guess the question wasn't stated very clearly. It actually composes of 4 separate ones:

    1. How does a TextBlock get its default color, if the client app doesn't provide any style, either programmatically or through xaml?
    2. How does a Label get its default color?
    3. How does a TextBlock get its default font size and font family, if the client app doesn't provide any style, either programmatically or through xaml?
    4. How does a Label get its default font size and font family?

    BTW, the questions are not about how to change or define styles for the color/font size/font family of a TextBlock or a Label, although they are somehow related. I think I already knew the answer for #2, that is a Label gets its color from SystemColors.ControlTextBrushKey and by overriding ConrolTextBrushKey like so:

    <SolidColorBrush x:Key="{x:Static SystemColors.ControlTextBrushKey}" Color="Red"/>
    

    You would be able to "globally" change color for Labels. After some research, I guess I also find the answer for #1: A TextBlock inherits the its foreground color from its containing Window, which by default gets its Foreground color from SystemColors.WindowTextBrushKey. By defining a color for the WindowTextBrush like so:

    <Window.Resources>
        <SolidColorBrush x:Key="{x:Static SystemColors.WindowTextBrushKey}" 
                         Color="Yellow"/>
    </Window.Resources>
    

    You would be able to change the "foreground" color for the TextBlocks inside the Window.

    Question #3 and #4 remain puzzles for me, but I am assuming they have to do with the SystemFonts.

    Hope this makes sense. I really like to know the answers as they have been bothering me for a while. Many thanks!

    Below is the original post:


    If you look into the style for a Label in the theme (for example "aero.normalcolor.xaml") that comes with Windows, you can find

    <Setter Property="Foreground" 
            Value="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}"/>
    

    Which sets the color for a Label. But there is no where the FontSize property is specified in the style, which I assume has something to do with the SystemFonts. For a TextBlock, it looks even more mysterious as the style for it in "aero.normalcolor.xaml" has only 4 lines:

    <Style x:Key="{x:Type TextBlock}"
                     TargetType="{x:Type TextBlock}">
            <Setter Property="TextWrapping"
                            Value="NoWrap"/>
            <Setter Property="TextTrimming"
                            Value="None"/>
        </Style>
    

    Where does a Label or a TextBlock get the values for its color and font size/family from, if the app doesn't set any, and where are those hooks in WPF?

    Edit:

    This is a test drive attempting to set the TextBlock color through SystemColors.ControlTextBrush (assuming that's where a TextBlock gets its default color from, which seems to be false):

    <Window x:Class="TestFontColor.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525">
    <StackPanel>
        <StackPanel.Resources>
            <SolidColorBrush x:Key="{x:Static SystemColors.ControlTextBrushKey}" Color="Red"/>
        </StackPanel.Resources>
        <Button Content="This is red."/>
        <Label Content="This is blue.">
            <Label.Resources>
                <SolidColorBrush x:Key="{x:Static SystemColors.ControlTextBrushKey}" Color="Blue"/>
            </Label.Resources>
        </Label>
        <TextBlock Text="TextBlock: This is still black."/>
    </StackPanel>
    

  • mobileTofu
    mobileTofu over 12 years
    SystemsColors doesn't seem to affect TextBlocks, though.
  • Pavel Gatilov
    Pavel Gatilov over 12 years
    @mobileTofu You must be doing it wrong. Rachel is right, if you put her sample brush to a ResourceDictionary it will override system settings. Try using ControlTextBrushKey instead of HighlightBrushKey to increase the effect. Also, try putting the brush to a higher-level logical tree item than the controls you want it to affect. Resources of a Label won't affect the Label, only its children.
  • mobileTofu
    mobileTofu over 12 years
    @Pavel Gatilov inline style resources for a Label do affect Label. Please see my edit above. Thanks.
  • mobileTofu
    mobileTofu over 12 years
    Please read the question before posting an answer. I don't believe either answer has provided any new information than that's already there in the original question. Many thanks.
  • mobileTofu
    mobileTofu over 12 years
    Hope my comment didn't come through as rude; if that's the case, I am sorry.
  • Pavel Gatilov
    Pavel Gatilov over 12 years
    @mobileTofu At this time I don't understand what your question is. Do you want to know why Labels behave differently from TextBlocks? Do you want to know how default colors and other settings are determined? Why aren't you satisfied with my or Rachel's answers?
  • Pavel Gatilov
    Pavel Gatilov over 12 years
    @mobileTofu Please, see my UPDATE 2 for answers to your rephrased questions.
  • mobileTofu
    mobileTofu over 12 years
    Sorry about the confusion. I guess I didn't state my questions clearly, which I updated (again), along with the attempt to answer them by myself. You said "You don't need to set those them wherever in order for them to work" and "supposedly depend on the system theme", I guess that's exactly where my puzzle is. I'd like to find out how the system or the WPF framework defines those default values, not about how the client app goes about providing its own to style a TextBlock or a Label control; although the two questions are somehow related. Hope this makes sense. Thanks!
  • mobileTofu
    mobileTofu over 12 years
    Thanks for the update #3. I guess my questions could also be rephrased as to what sits on top of the inheritance trees for those properties (foreground/font size/family).
  • Pavel Gatilov
    Pavel Gatilov over 12 years
    @mobileTofu Please, refer to my answers to your questions #3, 4 given in UPDATE 2. This answers them. I've also added more details on how the default settings of the WPF properties map to the WIN32 API functions ('Going deeper'). Check out if it is what you want.
  • mobileTofu
    mobileTofu over 12 years
    Thanks for the update. Looks like what I'm looking for. So how do I go about defining/changing MessageFontFamily and MessageFontSize so that I see a TextBlock or Label gets inherited, either through xaml, Windows GUI or programmatically?
  • user1040323
    user1040323 over 5 years
    Only TextElement.FontSize="xx" works. .FontFamily and .Foreground do not work. e.g. <Window TextElement.FontSize="16" TextElement.FontFamily="Comic Sans" TextElement.Foreground="Red"> ... </Window>