The official blog of the Windows Presentation Foundation Team
The Ribbon RTM release was built against .NET 3.5, but our October 2010 release of Ribbon includes both .NET 3.5 and .NET 4.0 Ribbon DLLs. With the v4.0 Ribbon, we have enabled ClearType on all of the Ribbon controls using RenderOptions.ClearTypeHint. WPF applications using RibbonWindow must also opt-in to enable ClearType for all content below the Ribbon.
This article describes ClearType technology and requirements and then specifies how a WPF Ribbon application enables ClearType. We refer to RibbonWindow and Ribbon applications specifically, but similar steps to enable ClearType apply for any WPF app that uses WindowChrome.
ClearType is a subpixel anti-aliasing technique for improving text smoothness. Wikipedia has a nice overview of the technology here. WPF supports ClearType and extends ClearType in .NET 4 by allowing app developers to electively use ClearType on surfaces that are otherwise considered transparent and hence inappropriate for ClearType. Read more about WPF support for ClearType here.
ClearType support in WPF has a couple requirements:
Here is some text rendering as ClearType (shown at 800% magnification):
Notice the red and the blue hues. These indicate the text is rendering on subpixel boundaries. Rendering this text on subpixel boundaries gives 3x higher horizontal resolution than rendering on pixel boundaries, although there is a chromatic cost – some color is introduced to create the smoothing effect. This snapshot was taken at 800% magnification, and when I zoom out to normal resolution the red and blue hues are unnoticeable and you see smooth text.
Normal WPF 4.0 Window will support ClearType by default, so you get it for free. However, if you are using RibbonWindow, you need to opt in using the RenderOptions.ClearTypeHint attached property (System.Windows.Media namespace, PresentationCore.dll). This is necessary because RibbonWindow extends glass into the client area using DwmExtendFrameIntoClientArea. (RibbonWindow claims the entire native window as client area so that it can draw the Quick Access Toolbar in what is normally non-client area. Therefore, RibbonWindow must extend glass into the client area to attain the appearance of a normal Aero window.)
It is only necessary for RibbonWindow apps to set RenderOptions.ClearTypeHint for their Aero themes, but setting ClearTypeHint.Enabled for all themes shouldn’t hurt.
All of the WPF Ribbon controls render as ClearType as long as they are rendering against solid backgrounds (most controls are). Examine this screenshot:
Notice how the “Home” RibbonTab is rendering as ClearType with warm and cold hues, while the RibbonTitlePanel’s text is using grayscale anti-aliasing. This screenshot was taken on Win7 Aero, and the RibbonTitlePanel renders directly on glass, so it doesn’t support ClearType. The grayscale text is choppier, while ClearType offers a general improvement in text clarity. The text sharpening provided by ClearType is a cumulative effect, so the improvement in clarity becomes more evident at the document/app level.
The “Home” tab has ClearType “because the v4.0 Template for RibbonTabHeader sets RenderOptions.ClearTypeHint=“Enabled” on its “InnerBorder” element. Other Ribbon controls set ClearTypeHint in their templates also, and the Ribbon sample apps (e.g. RibbonWindowSample.exe) set ClearTypeHint similarly in their XAML.
While Ribbon is fully ClearType-enabled, an app using Ribbon must opt-in to ClearType for the Aero theme. To achieve this, we simply make sure RenderOptions.ClearTypeHint=“Enabled” is set wherever text is hosted. Examine the following XAML:
<Grid x:Name="LayoutRoot" ...>
<ribbon:Ribbon x:Name="Ribbon" ... />
<TextBlock Text="ClearType ENABLED." RenderOptions.ClearTypeHint="Enabled"/>
<TextBlock Text="ClearType OFF."/>
Running this on Win7 Aero produces the following text rendering:
Notice ClearType rendering in the top TextBlock, which opts in to ClearType. Besides the chromatic differences, from this screenshot it’s not immediately obvious what improvements ClearType brings to the table. Bear in mind that ClearType rendering creates an accumulative effect to improve general text crispness.
Generally one should set RenderOptions.ClearTypeHint=“Enabled” at some root element, since the setting propagates down the visual tree unless another IRT (Intermediate Render Target, see next section) gets in the way. For example:
<Border Grid.Row="1" RenderOptions.ClearTypeHint="Enabled">
<Button Width="Auto" HorizontalAlignment="Left">body has</Button>
Notice that we set ClearTypeHint=“Enabled” on the Border element below the Ribbon rather than on the parent Grid that contains everything. This was deliberate – the Ribbon’s quick access toolbar and title draw over the transparent glass at the top of the window, and setting ClearTypeHint=“Enabled” for text over transparent backgrounds may cause rendering issues.
IRT stands for Intermediate Render Target. An IRT is a common WPF graphics term used to refer to a surface that a tree of WPF visuals render to. Every separate visual tree (e.g. contents of a Popup in WPF) renders to a separate IRT. In addition, applying a Clip/Opacity to a Visual causes a new IRT to be generated.
ClearTypeHint, when set, propagates to the subtree under that Visual that renders to the same IRT. If a descendant node in this subtree has a Clip applied to it or causes a new IRT to be created for another reason, it no longer honors the ClearTypeHint settings. These settings will need to be redefined on a Visual within the scope of this new IRT. A common instance where this behavior manifests is in the case of a ScrollContentPresenter of a ScrollViewer. A ScrollContentPresenter inherently clips the contents that are beyond the viewport. By doing so, it causes its contents to be rendered to a separate IRT.
Now consider a RichTextBox hosted in the content pane of a RibbonWindow. A RichTextBox’s built-in template uses a ScrollViewer that contains a ScrollContentPresenter. Thus to turn on ClearType for text rendered within this ScrollContentPresenter, we must do two things:
The attached sample code demonstrates such usage. Similar techniques have been implemented in the RibbonControlsLibrary to enable ClearType for the various subcomponents within the Ribbon. For further reference, Lester Lobo’s blog discusses IRTs and when to use ClearTypeHint in WPF.
As seen in this article’s screenshots, text rendering as ClearType has red and blue hues since glyphs cut across subpixel boundaries. It can be difficult to verify ClearType rendering at normal resolution, so we use a magnification technique to zoom in. Windows ships with a magnifier accessibility tool we can launch from the Start Menu:
When you magnify 800%-1000%, you can readily see the ClearType effect. The magnifier’s Full screen mode works great on Aero but isn’t available on other themes, so I often use MSPaint to magnify screenshots on non-Aero themes.
ClearType is only available in .NET 4.0, but some WPF apps and custom controls may want to support both .NET 3.5 and 4.0, lighting up with ClearType on .NET 4.0. To support both platforms from a single codebase, some conditional compilation is required.
Ribbon itself requires conditional compilation. The Microsoft Ribbon for WPF Source and Samples MSI includes a perl script that pushes XAML files for the Ribbon sample apps through the C preprocessor to create separate 3.5 and 4.0 XAML. The 4.0 XAML has ClearTypeHint specified in several control templates, and #ifdef directives in the XAML direct the conditional compilation.
Sample Code for this article is attached.
Patrick, thank you!!! I beat my head against this wall for awhile last week. I sprinkled that ClearTypeHint all over my XAML and got ClearType to work in every place in my app except the one place I really wanted it: the caption text underneath image thumbnails for items in a ListBox control. Space is at a premium here and this text needs to be as clear as possible. The DataTemplate for these items consists of a Border containing a few Grids, an Image, and a TextBlock. The ListBox control uses a WrapPanel to get the kind of layout you see in say, large icon view in Explorer. Then the ListBox is inside a Grid which is inside a DataTemplate for a TabItem of a TabControl which is inside a Grid and so on.
It turned out the key piece I was missing was setting a solid background color. If I add Background="White" to the Border of the item's DataTemplate or just the TextBlock itself, then ClearTypeHint actually takes effect for the text inside. I hadn't specified any background before so it wasn't like I'd gone out of my way to do some transparent background. This tip about setting an opaque background is really key. I'd read about this issue elsewhere before finding your blog post, but I didn't see this one crucial bit of information. Now I've got to make sure the background is only set when the item is not selected so it doesn't screw up the item's appearance when selected, but I can work that out.
This is really a nasty bit of low level detail that the platform should be taking care of automatically. Failing that, it would be nice if ClearTypeHint would just work regardless of where you put it or whether or not an opaque background has been set. Failing that, there should probably be an error in the debug output or something if what was requested by ClearTypeHint was not possible because of these implementation details. Finally, the documentation for ClearTypeHint should be improved to have the level of detail you have in this blog post - especially the tip about the opaque background.
I realize this problem is a tricky one that hasn't come up until well after WPF was written, and we're probably lucky to have ClearTypeHint at all. I hope you guys can improve this in a future version of WPF though. Otherwise there's probably going to be an awful lot of grayscale anti-aliasing going on out there. (Not disastrous, but just another thing setting WPF apps apart.. not in a good way.)
Now if I could just get the text for some of these items to stop randomly blurring when I try to use cached composition, I'd be golden!
@Tom I'm glad you found this post helpful. Thanks for the detailed feedback about ClearTypeHint! It can be tricky to know exactly where it needs to be used, and writing this post was a learning experience for me. Looking at the RenderOptions.ClearTypeHint documentation, I did find this line about using an opaque background under the Remarks section: "Assign an opaque background that is as close as possible in the visual tree to the text."
I'll make sure the PM leads and the graphics team see your feedback on ClearTypeHint. I was talking to Rob Relyea & Troy Martez about ClearType in WPF yesterday, and we would indeed like to get better default ClearType behavior in WPF. Thanks.
WOW Great post.
I've been trying to get ClearType work for the last couple of days. It's a pain I must say. This post helped me a lot. I have found ClearType to be very inconsistent in RibbonWindow.
1) When I enabled UseLayoutRounding in Ribbon, some of the RibbonTab Headers went to Greyscale Cleartype.
2) I can't get Cleartype to work in a listView that uses a VirtualizingStackPanel.
3) Simple Textboxes and Buttons are also reveting to Greyscale Cleartype. I just can't get these work properly.
In concluion: it still needs a lot of work.
Patrick, thanks again, that's good to hear. I double checked the docs and you're right of course, it's right there in plain sight and seems familiar enough. Not sure how I missed it before, sorry about that!
By the way, there's also a note there that says "On many controls, the ClearTypeHint attached property has no effect unless you set a non-opaque background behind the text." I wonder if this should say "opaque" instead of "non-opaque".
@James - Glad you found this helpful! Agreed, enabling ClearType in RibbonWindow is a pain because ClearType rendering is turned off for RibbonWindow's entire tree by default and one must set ClearTypeHint="Enabled" every time the tree branches into a new IRT. This is certainly a subpar experience that we would like to improve upon (ideally getting the expected ClearType experience by default for RibbonWindow).
#1 - I tried setting Ribbon.UseLayoutRounding, but still saw the RibbonTabHeaders render in ClearType. Are you styling them or setting clip or Background in a way that would affect ClearType rendering? I'm happy to take a look if you have a repro or more detailed repro steps.
#2 - I was able to get ClearType in a ListView that uses VirtualizingStackPanel. In ListView.ItemTemplate, I include a Border element with RenderOptions.ClearTypeHint="Enabled" and Background="White" (the same as the RibbonWindow), and with this I get clear type for the ListViewItems. You may want to try something similar.
#3 - TextBox contains new IRTs in its tree but Button does not. Button should be able to inherit RenderOptions.ClearTypeHint. I'll check with our Text team about the best way to enable ClearType for TextBox since it seems tricky.
I agree with your conclusion that work is needed here. We have filed a bug to investigate and improve customer experience for ClearType in RibbonWindow.
@Tom - You're right, that note should say "opaque" instead of "non-opaque". Thanks, we'll get this fixed!
@James I spoke to Varsha, and we have a good example of how to enable ClearType for TextBox family of controls in our RibbonWindowSample. TextBox has a ScrollViewer in its template that is an IRT. Basically, to enable ClearType for TextBox you restyle ScrollViewer and set ContentTemplate to include a Border element with an opaque background and RenderOptions.ClearTypeHint="Enabled". Look for this Style in the v4.0 UserControlWord.xaml. The default Style for RibbonTextBox also restyles ScrollViewer like this.