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.