WPF: Changing default text style
What is the proper way to change text color, font, or size throughout an application?
The best way I know so far is to create a named style targeting type Control
(not TextBlock)
and manually apply it to all top-level windows in the application. Properties like FontSize
and FontFamily
are inherited almost universally. Foreground
color is overriden in many controls. You will have to style
them separately. This is actually a good thing: depending on your theme you may or may not want your button text to be the same
color as regular text.
This is how the results of the styling look like:
Before styling | After styling |
---|
And this is the code:
App.xaml MainWindow.xaml Full code
Why overriding implicit TextBlock style is not a good idea
If we put the implicit style in application resources, it works too well. If we put the implicit style in main window resources, it is too weak.
Implicit style in application resources
This style affects all text blocks in the application, except those with their own explicit style. It becomes impossible to change appearance of buttons, labels and other controls if corresponding properties are defined in the TextBlock style. Notice how the "Blue Italic Button" is now neither blue nor italic.
<!-- App.xaml --> <Application.Resources> <!-- Don't do this! --> <Style TargetType="{x:Type TextBlock}"> <Setter Property="Foreground" Value="Red" /> <Setter Property="FontSize" Value="14" /> <Setter Property="FontFamily" Value="Courier New" /> <Setter Property="FontStyle" Value="Normal" /> </Style> </Application.Resources>
NB: You may find an advice
to override the data template for System.String
to cancel the negative effects of an implicit TextBlock style.
Overriding data template for String is also not a good idea.
Implicit TextBlock style in Window resources
If we define an implicit TextBlock style in main Window resources, we get too little overriding. The style does not apply to TextBlocks
inside data templates. Amazingly, implicit style for Label
does affect labels inside data templates.
This is not a bug. It was intentionally
designed to
protect us from the evils of too much overriding. Implicit styles for controls (Label
, Button
,
CheckBox
) penetrate all the way through, but implicit styles for non-controls (TextBLock
, Rectangle
)
stop at data template/ContentPresenter
boundaries.
<!-- MainWindow.xaml --> <Window ...> <Window.Resources> <Style TargetType="{x:Type TextBlock}"> <Setter Property="Foreground" Value="Red" /> <Setter Property="FontSize" Value="14" /> <Setter Property="FontFamily" Value="Courier New" /> <Setter Property="FontStyle" Value="Normal" /> </Style> </Window.Resources> ... </Window>
More Info
Why implicit TextBlock style takes over everything.
Why overriding DataTemplate for System.String is a bad idea.
Conclusion
It may be counter-intuitive, but overriding text traits is better done by tweaking the properties of the parent controls rather than defining a TextBlock style. TextBlocks then inherit the properties from parents. Attempts to define an implicit style for TextBlock lead to either too much, or too little overriding.
Feedback
Questions? Comments?
Drop me a line
Copyright (c) Ivan Krivyakov. Last updated: October 26, 2014