Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / multimedia / GDI+

WinForms Tab Control with properly drawn bottom tabs

4.83/5 (41 votes)
20 Feb 2014CPOL5 min read 193.2K   9.7K  
How to correctly draw WinForms Tab Control with bottom alignment when visual styles are enabled

Image 1

Using UxTabControl

Introduction

Most developers face the same problem when using a tab control with a tab alignment other than Top: when visual styles are enabled, the tabs are drawn incorrectly (to say more precisely - in top orientation only). The same thing happened to me one day. I had a task to convert an old .NET 1.1 application to run under .NET Framework 2.0. I wanted to add visual styles support, and oops - we have a known tab problem. I had been searching the web and had found some solutions, but none of them satisfied me fully. I decided to write my own control UxTabControl by subclassing System.Windows.Forms.TabControl.

You might find my control useful because I think many of you still use Windows Forms and not WPF, and Microsoft hasn't added correct tab drawing for SysTabControl32 even in Windows 8.1. Those guys just require only the top tabs for you to get your application Microsoft certified (by the way, Apple has implemented their tabs correctly in any orientation from stock; you know what I mean if you used Interface Builder deep enough at least once).

Background

I've used the Adi DEDIC article here on CodeProject as a starting point so you can read the Background section from there. Adi explains how to rotate tabs and draw them. My control uses a similar technique. But Adi's control is written in C++ and uses MFC, mine is written mostly in managed code though it uses some platform interops. I have also used some tips about the tab scroller from Mick Doherty's site. You can find the bottom tab control there also in his implementation, but without the source code.

Using the Code

The simplest way of using the control is to add it to your toolbox. To do this, just right-click on the preferred section of the toolbox and then select "Choose items..." in the popped up menu; click "Browse" in the ".NET Framework Components" tab and look for UxTabControl.dll. You're done! Now, you should see UxTabControl in your toolbox, and you can drag it on your form like any other control.

If you don't want to use it in the way described above for some reasons (you aren't using Visual Studio but Notepad and command prompt, for example), you have to add UxTabControl.dll to your project reference libraries. After that, in the code where you are planning to use the control, add the following directive:

C#
using VSControls;

In Visual Basic:

VB.NET
Imports VSControls

In C++/CLI:

C++
using namespace VSControls;

Now, you can create and manipulate UxTabControl the same way as System.Windows.Forms.TabControl

C#
UxTabControl myControl = new UxTabControl();
myControl.Location = new Point(10, 10);
//other code you need

In Visual Basic:

VB.NET
Dim myControl As New UxTabControl
myControl.Location = New Point(10, 10)
'other code you need

In C++/CLI:

C++
UxTabControl^ myControl = gcnew UxTabControl();
myControl->Location = Point(10, 10)
//other code you need

The recommended way to open all the projects and solutions is to use Visual Studio 2013. They all target .NET Framework 4.0 Client Profile (except C++/CLI). If you don't happen to have Professional or more advanced edition of the IDE available, you can download the express edition for Windows desktop from the Microsoft website

Requirements & Limitations

  • .NET Framework 4.0 or newer is required to run the code. Still, after certain modifications, I believe that it's possible to compile the code with older versions of the framework, but not older than 2.0.
  • Custom drawing is not guaranteed to work properly with visual styles other than Microsoft's ones.
  • Supported Windows systems: Vista, 7, 8, 8.1 and their server counterparts. Of course, visual styles must be enabled; otherwise, drawing will be done by the default Windows engine (that's the way I've designed it).
  • Left and right tab alignments aren't supported. I suppose it is not very convenient for a user to lean the head towards the shoulder for a tab's caption to be read, don't you think so? But, if you badly need that feature, you can implement it by yourself.

Points of Interest

  • This article shows how you can subclass some standard .NET controls and override some properties to reach the desired effect.
  • You will learn how to use the System.Windows.Forms.VisualStyles namespace to draw parts of some controls (tab control, in our case).
  • Also, the code shows how to override WndProc to react on some Windows messages.

History

  • 20.03.2009 - Version 1.0
    • Initial version
  • 7.03.2010 - Version 1.0.1
    • Fixed bug with tab text (thanks to SierraMike for reporting). Now text is drawn by GDI instead of GDI+ (I found the solution for "memory bitmap + TextRenderer + ClearType enabled" problem) and so it fits inside tabs
  • 22.02.2013 - Version 1.0.2
    • The control now has a sort of a "transparent" background, i.e., it draws its parent's background on its surface before drawing itself.
    • The RightToLeft and RightToLeftLayout properties are no longer disabled. They were disabled in previous versions due to painting problems.
    • The control has been renamed to UxTabControl (after uxtheme.dll). The previous name was bound to a particular version of Windows and that is not quite accurate.
    • The support for Windows XP and 2003 has been dropped. I consider these operating systems obsolete.
  • 2.02.2014 - Version 1.0.3
    • Some people didn't like unsafe code used in the C# project. Well, that one has been replaced with the help of the magic structure System.Runtime.InteropServices.GCHangle. It's the unified approach in all the projects you can download from this article.
    • A C++/CLI project has been added for the complete set. 

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)