WPF: Enabling ClearType On a TextBox
If you try to improve the readability and smoothness of the text in your WPF application by simply setting the RenderOptions.ClearTypeHint attached property to System.Windows.Media.ClearTypeHint.Enabled on a TextBox in a transparent window, the text in the TextBox will still not be rendered using ClearType.
This article explains how to enable ClearType – a subpixel anti-aliasing technique for improving text smoothness – also for TextBoxes.
The issue is easy to reproduce; create a new window, set its AllowTransparency property to True and its WindowStyle property to None and add a TextBlock and a TextBox to the root panel of the window:
<Window x:Class="WpfApplication1.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
Title="Window1" Height="300" Width="300"
WindowStyle="None"
AllowsTransparency="True">
<StackPanel>
<TextBlock Text="ClearType?" RenderOptions.ClearTypeHint="Enabled" />
<TextBox Text="ClearType?" />
</StackPanel>
</Window>
Now, if you run the application with the new window being displayed and use the Magnifier tool ([Windows key] + [+] or Start -> Settings -> Ease of Access -> Magnifier on Windows 10) to enlarge the contents on the screen, you will notice that there is no ClearType applied to the rendered text in neither the TextBlock nor the TextBox:
https://magnusmontin.files.wordpress.com/2016/07/cleartype1.png?w=340&h=165
It may be a bit difficult to verify whether the text is actually rendered using ClearType at first but when you use the magnifier and compare an element with ClearType enabled to another element with no ClearType enabled you should be able to see the difference.
You could easily apply ClearType enabled text for the TextBlock by simply setting the attached RenderOptions.ClearTypeHint to Enabled on it:
<TextBlock FontSize="12" Text="ClearType?" RenderOptions.ClearTypeHint="Enabled" />
But if you try do the very same thing for the TextBox nothing happens:
https://magnusmontin.files.wordpress.com/2016/07/cleartype2.png?w=335&h=180
Note the difference in the egdes and the readability of the text in the TextBlock and the TextBox. The text in the TextBlock has red and the blue hues which indicates that the text is rendering on subpixel boundaries and ClearType is enabled whereas the the text in the TextBox is rendered using grayscale anti-aliasing.
So how to fix this? Since ClearType rendering requires the background to be fully opaque and WPF disables ClearType when it detects that the buffer into which text is drawn could have a transparent background, it turns out that you need to modify the ContentTemplate of the ScrollViewer element that is part of the default control template for the TextBox control to be able to enable ClearType for the TextBox.
You can right-click on a TextBox control in design mode in Visual Studio 2012 or later and select the “Edit template” option and then the “Edit a copy…” option to copy the default template into your XAML markup. You can then simply set the ContentTemplate property of the PART_ContentHost” ScrollViewer element to a Grid that has a Background and the RenderOptions.ClearTypeHint attached property set to Enabled:
<ScrollViewer x:Name="PART_ContentHost" Focusable="false" HorizontalScrollBarVisibility="Hidden" VerticalScrollBarVisibility="Hidden"
Background="{TemplateBinding Background}">
<ScrollViewer.ContentTemplate>
<DataTemplate>
<Grid Background="{Binding Background, ElementName=PART_ContentHost}" RenderOptions.ClearTypeHint="Enabled">
<ContentPresenter Content="{Binding Path=Content, ElementName=PART_ContentHost}"></ContentPresenter>
</Grid>
</DataTemplate>
</ScrollViewer.ContentTemplate>
</ScrollViewer>
Below is the complete TextBox style that was rendered by Visual Studio on a Windows 10 computer with the above mentioned modifications to the ScrollViewer element:
<SolidColorBrush x:Key="TextBox.Static.Border" Color="#FFABAdB3"/>
<SolidColorBrush x:Key="TextBox.MouseOver.Border" Color="#FF7EB4EA"/>
<SolidColorBrush x:Key="TextBox.Focus.Border" Color="#FF569DE5"/>
<Style x:Key="ClearTypeEnabledTextBoxStyle" TargetType="{x:Type TextBox}">
<Setter Property="Background" Value="{DynamicResource {x:Static SystemColors.WindowBrushKey}}"/>
<Setter Property="BorderBrush" Value="{StaticResource TextBox.Static.Border}"/>
<Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}"/>
<Setter Property="BorderThickness" Value="1"/>
<Setter Property="KeyboardNavigation.TabNavigation" Value="None"/>
<Setter Property="HorizontalContentAlignment" Value="Left"/>
<Setter Property="FocusVisualStyle" Value="{x:Null}"/>
<Setter Property="AllowDrop" Value="true"/>
<Setter Property="ScrollViewer.PanningMode" Value="VerticalFirst"/>
<Setter Property="Stylus.IsFlicksEnabled" Value="False"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type TextBox}">
<Border x:Name="border" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" SnapsToDevicePixels="True">
<ScrollViewer x:Name="PART_ContentHost" Focusable="false" HorizontalScrollBarVisibility="Hidden" VerticalScrollBarVisibility="Hidden"
Background="{TemplateBinding Background}">
<ScrollViewer.ContentTemplate>
<DataTemplate>
<Grid Background="{Binding Background, ElementName=PART_ContentHost}" RenderOptions.ClearTypeHint="Enabled">
<ContentPresenter Content="{Binding Path=Content, ElementName=PART_ContentHost}"></ContentPresenter>
</Grid>
</DataTemplate>
</ScrollViewer.ContentTemplate>
</ScrollViewer>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsEnabled" Value="false">
<Setter Property="Opacity" TargetName="border" Value="0.56"/>
</Trigger>
<Trigger Property="IsMouseOver" Value="true">
<Setter Property="BorderBrush" TargetName="border" Value="{StaticResource TextBox.MouseOver.Border}"/>
</Trigger>
<Trigger Property="IsKeyboardFocused" Value="true">
<Setter Property="BorderBrush" TargetName="border" Value="{StaticResource TextBox.Focus.Border}"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<MultiTrigger>
<MultiTrigger.Conditions>
<Condition Property="IsInactiveSelectionHighlightEnabled" Value="true"/>
<Condition Property="IsSelectionActive" Value="false"/>
</MultiTrigger.Conditions>
<Setter Property="SelectionBrush" Value="{DynamicResource {x:Static SystemColors.InactiveSelectionHighlightBrushKey}}"/>
</MultiTrigger>
</Style.Triggers>
</Style>
If you then set the Style property of the TextBox in the transparent window to this style:
<TextBox FontSize="12" Text="ClearType?" Style="{StaticResource ClearTypeEnabledTextBoxStyle}" />
…the text in the TextBox will be rendered as ClearType text:
https://magnusmontin.files.wordpress.com/2016/07/cleartype4.png?w=345&h=170