Things They Didn't Fix in Whidbey - Fonts in Windows Forms

I've been developing with the .NET framework and Visual Studio .NET for several years now.  Like most developers, I've accumulated my list of annoyances, hassles, and mistakes that I've encountered using the tools over that time. As an optimistic chap, I cling to the hope that these problems will be addressed in the next version of the toolset.

Well, the next version is here. The improvements are vast, the productivity gains substantial. Naturally, as I've beeng playing with the newest bits (ok, more than play at this point - I'm writing production code on the VS2005 Feb CTP bits), I've been checking to see if MS has addressed any of the problems that have plagued me in the past. Sometimes the news is good, sometimes not. From the title of this post, you can guess which I'm focusing on here. I've already blogged about one such issue. Here's another.

In the .NET Framework 1.x, Windows Forms is really the poor step-child to Web Forms. Yes, MS gave us a reasonably nice object-oriented GUI framework for rich client apps. But let's face it - apps generated with the out-of-the-box controls are the equivalent of circa-1995 Windows applications. One particularly egregious issue with Windows Forms 1.x is with default font handling. Specifically, a Windows Forms application uses the Microsoft Sans Serif font for its controls when running on Windows XP rather than Tahoma, the default system font for XP.

Why is Microsoft Sans Serif used? If you use Reflector to poke in the Control class, you'll find a property called DefaultFont. This is the font that is used if the font isn't explicitly set on the control or its parent. Looking through the source for the property getter, you'll find the following key line of code:

IntPtr ptr1 = UnsafeNativeMethods.GetStockObject(0x11);

So what is stock object 0x11 (decimal 17)? In WinGDI.h, this corresponds to DEFAULT_GUI_FONT. If you look at the MSDN help for GetStockObject, it all becomes clear. Or, maybe not. The first line of help for DEFAULT_GUI_FONT is "Default font for user interface objects such as menus and dialog boxes". OK, that sounds right. Unfortunately, the second two sentences say "This is MS Sans Serif. Compare this with SYSTEM_FONT." So that explains why MS Sans Serif.

Jump down to the description for SYSTEM_FONT, however, and you'll see the following: "By default, the system uses the system font to draw menus, dialog box controls, and text". Erm. Hmm. That sounds familiar, doesn't it? The next two lines clarify "Windows 95/98 and Windows NT: The system font is MS Sans Serif.  Windows 2000/XP: The system font is Tahoma".

So it looks suspiciously like someone at Microsoft simply plugged the wrong value into GetStockObject. Now, I'm not a Win32 GDI expert, so maybe there's some history here that explains why they used DEFAULT_GUI_FONT instead of SYSTEM_FONT (Raymond, are you out there?).

OK, so here comes Whidbey. Windows Form 2.0. Finally, Windows Forms gets first class treatment. Slick look-and-feel, richer control set, ClickOnce deployment - MS starts pushing the Smart Client in a big, big way. So of course they're going to fix this font thing, right? Bzzt, sorry, wrong, thank you for playing. No, Windows Forms in Whidbey still uses MS Sans Serif as the default font. In other words, the newest generation of Microsoft's premiere development tool, on Microsoft's latest development platform, generates UIs that don't follow their own UI guidelines.

In all fairness, I'm assuming that MS couldn't change the default font to maintain backward compatibility with existing .NET apps. There's a Ladybug report on this issue describing how to deal with the problem in code, but it's a hack, and there's not a good design-time solution. A small bit of good news is that the new MenuStrip control uses the correct font.

Ideally, I think design-time font selection should work much like color selection, allowing you to select a system font or a custom font. In fact, I started writing a TypeConverter to give you this, but ran into a bug that prevents you from overriding a class TypeConverter with a property TypeConverter. So for the moment there doesn't seem to be a great solution.

10 Comments

  • maybe they'll correct it in the final version?

  • Thanks for mentioning this. I researched the exact same topic a while ago, with the exact same results, but had forgotten all (well, most) about it. Now you've reminded me, I'll have another look at the issue.



    Oliver

  • Eric,

    The bug report that I linked to indicates that MS is not planning on fixing this for Whidbey final release.

  • Thanks Kevin Dente. You rock.

    And yes, some of us care about details like this. It's a shame Microsoft doesn't seem to.

  • Still not fixed in Beta 2 of VS 2008. Pathetic.

  • apple would never do this

    thats why all windows applications feel so clunky and like they were all made in separate caves with no contact with the outside world

  • Gee, imagine if there was some technology that let you define a standard form, say, that other forms would "inherit" from. You could set non-default properties in this form and "reuse" it to create new forms with those properties. You could even create two forms and create a new form that combined features from both. Wonder what a technology like that would be called?

  • "Gee, imagine if there was some technology that let you define a standard form, say, that other forms would "inherit" from. You could set non-default properties in this form and "reuse" it to create new forms with those properties. You could even create two forms and create a new form that combined features from both. Wonder what a technology like that would be called?

    A. L. Flanagan"

    It would be called Forms Inheritance, which is useless (at least in VB.NET) because all base form controls are locked on the child form. Since you couldn't add controls to a container control in the base class or manipulate a data control in the base class, which would likely be the only reason for forms inheritance in the first place, it's useless.

  • @HardCode - You might want to consider adjusting your base class controls visibility level. Changing these from their default 'private' to, say, 'protected' makes Forms Inheritance quite useful pretty suddenly ;)

    (In VS Forms Designer, look for the 'Modifiers' entry in the controls properties Window)

  • WPF?

    re: "Gee, imagine if there was some technology that let you define a standard form, say, that other forms would "inherit" from. You could set non-default properties in this form and "reuse" it to create new forms with those properties. You could even create two forms and create a new form that combined features from both. Wonder what a technology like that would be called?"

Comments have been disabled for this content.