Click here to Skip to main content
11,438,007 members (43,533 online)
Click here to Skip to main content

Adding XP Themes to Custom .NET Controls

, 31 Aug 2003 CPOL
Rate this:
Please Sign up or sign in to vote.
Rendering your own theme parts with the Windows XP UxTheme API

Introduction

This article is about exploring the ability to create custom controls in the .NET platform, that make use of Windows XP's visual styles and themes. To that end I have included a couple of fairly simple controls that mimic some of the behaviors that Windows Explorer implements in XP.

Background

This work is really an extension of what I'm doing at my day job. The project I'm working on right now is a new, .NET version of an existing application. The existing version is your standard MFC app and has all of the familiar Windows 95 era GUI idioms. As part of the new version, we are attempting to add a much-needed update to the user interface.

Part of this effort is the desire to conform to Windows XP user interface styles and guidelines in all parts of the application.

The nice thing about writing a user interface in .NET is the ease with which controls can be created and wired together. Compared to MFC, with its message maps, SubclassDlgItems and WndProcs, concentrating on the needs of the user rather than the needs of the compiler is finally a possibility.

As much as I prefer this new way of creating robust user interface features, I do feel that there is one glaring omission from the .NET framework's System.Windows.Forms namespace: support for themes.

Sure, the Button class will pick the correct look and many of the other controls will take on a themed appearance, but as other articles on Code Project have pointed out, the support for themeing in .NET controls is only superficial.

This is especially true if you are creating your own controls, that need to define there own graphical features.

In order to ease the access to Windows XP's themeing API, I've created some wrapper classes to the UxTheme DLL. This set of controls makes use of that library.

Using the code

The trick to creating a theme aware custom control is that, you really have to take two paths through the painting process. One has to work on non-XP operating systems and on XP when themes are not enabled. The other has to work when the application is being themed on Windows XP.

The controls ExplorerBar, ExplorerGroup, SideBar and their common base class ThemeablePanel demonstrate this approach.

They all override OnPaintBackgournd and/or OnPaint and decide what sort of rendering to do, based on whether themeing is currently enabled. If it is not, they basically just call the base class functionality, and everything works as normal. If it is, they use the managed theme API to get the correct ThemePart objects that they want to use for their themed representation, and use it to draw the appropriate background and foreground features.

To do this the painting code finds the correct theme part and state, and renders itself using that object:

protected override OnPaint( PaintEventArgs e )
{
    ThemeInfo info = new ThemeInfo();
    WindowTheme window = info["EXPLORERBAR"];

    if ( UxTheme.IsAppThemed && window != null )

    {
        ThemePart part = window.Parts["HEADERCLOSE"];
        part.DrawBackground( e.Graphics, 
              new Rectangle( 0, 0, Bounds.Width, Bounds.Height );
    }
    else
       base.OnPaint( e );
}

That's about all there is to it.

You'll also notice that these controls also take over the rendering of some of their constituent controls by doing custom rendering in their Paint events. One could go an extra step, and make those constituent controls do their own theme rendering, by creating some derived classes. That is probably the direction I will head as things get more complex, but both approaches work.

Another thing you'll notice right away is that, there a number of classes derived from the common .NET controls like Label and PictureBox with names like ThemeLabel and ThemePictureBox. The reason for this is that, the .NET control classes don't like rendering themselves on a theme textured window (or at least I haven't been able to figure out how to get them to do so). Even when set to be transparent, there are visible artifacts around their edges when rendered over a themed background.

To correct this, you'll notice that all of these controls have a single method that overrides OnPaintBackground:

protected override void OnPaintBackground( PaintEventArgs pevent )
{
    if ( UxTheme.IsThemeDialogTextureEnabled( this.Parent ) && !DesignMode )
        UxTheme.DrawThemeParentBackground( this, 
           pevent.Graphics, new Rectangle( 0, 0, Width, Height ) );            
    else
        base.OnPaintBackground (pevent);
}

This override paints the control correctly on a themed background by rendering the background of the parent window rather than the window itself.

Another important point is that the user can change or disable themes at any point during the lifetime of your control. For this reason it is dangerous to hold on to any WindowTheme, ThemePart or ThemePartState object for any longer than a single paint operation. This ensures that your control will always paint correctly even if the environment changes. If it imposes a performance issue with reacquiring these objects with every paint, attach to the Microsoft.Win32.SystemEvents.DisplaySettingsChanged event, and dispose off and refresh your theme objects there.

Points of interest

The first control I worked on was the ExplorerBar class. After working on it an entire weekend (when I should have been outside enjoying the last of a beautiful Minnesota summer), I thought I pretty much had it nailed. I had been switching between the standard XP Blue Luna theme and the non-themed version of XP. So just to see how it looked in the green version of Luna, I switched over to the Olive color scheme.

And guess what! My ExplorerBar was still blue. After hours of scratching my head, digging and re-digging through the API it, began to dawn on me: Windows Explorer doesn't use UxTheme to render its ExplorerBar, even though the theme API defines parts and states for that type of control. Well it turns out that Windows Explorer uses yet another DLL named ShellStyles.dll to render its ExplorerBar, apparently bypassing UxTheme altogether.

My suspicion is that UxTheme is really not really fully cooked, and that it wasn't up to the requirements of Windows Explorer at the time they were developing it, and perhaps still isn't.

Regardless, this leaves the rest of us kind of out in the cold, because most of the custom themes I've looked at don't bother to redefine the ExplorerBar themes defined in UxTheme, but rather use the ones defined by VisualStyles.dll. So no matter what theme you choose, the ExplorerBar in this library will look like the Blue Luna version.

Is this a bug in my implementation? I'd like to say, no it isn't, because there's obviously an abstraction leak in the UxTheme API and it's really a bug there and in Windows Explorer. But I don't have $49 billion in cash reserves, so in reality the answer is probably yes from a user's perspective.

The fix, unfortunately, is to figure out how to dig the bitmaps out of VisualStyles.dll and render them in the correct places (if anybody's already done this and would like to share the code I'd love to see it).

History

  • 08/26/2203 - Initial release

License

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

Share

About the Author

Don Kackman
Team Leader Starkey Laboratories
United States United States
The first computer program I ever wrote was in BASIC on a TRS-80 Model I and it looked something like:
10 PRINT "Don is cool"
20 GOTO 10
It only went downhill from there.

Hey look, I've got a blog
Follow on   Twitter

Comments and Discussions

 
QuestionVista compatiblty? Pin
The Dogcow Farmer29-Aug-08 4:45
memberThe Dogcow Farmer29-Aug-08 4:45 
AnswerRe: Vista compatiblty? Pin
Don Kackman29-Aug-08 8:33
memberDon Kackman29-Aug-08 8:33 
Generalman you are from future, cool ;} Pin
radioman.lt@gmail.com11-Dec-07 20:45
memberradioman.lt@gmail.com11-Dec-07 20:45 
JokeRe: man you are from future, cool ;} Pin
Don Kackman27-Jul-08 8:33
memberDon Kackman27-Jul-08 8:33 
Hehe - I travel back in time to post articles in antique languages. In 2203 we are up to the .NET Framework 124.5 and Y#.
QuestionHow can I move this to .Net 2? Pin
fewfewfewfgwew4-Mar-06 17:02
memberfewfewfewfgwew4-Mar-06 17:02 
AnswerRe: How can I move this to .Net 2? Pin
1tg464-Mar-06 17:44
member1tg464-Mar-06 17:44 
GeneralRe: How can I move this to .Net 2? Pin
John Tan Jin Kiat20-Apr-06 1:21
memberJohn Tan Jin Kiat20-Apr-06 1:21 
QuestionRe: How can I move this to .Net 2? Pin
onlydeepak4u10-May-07 0:51
memberonlydeepak4u10-May-07 0:51 
AnswerRe: How can I move this to .Net 2? Pin
dttvn20-Aug-07 13:44
memberdttvn20-Aug-07 13:44 
GeneralFree library Pin
Stephen Lamb16-Oct-05 18:39
memberStephen Lamb16-Oct-05 18:39 
GeneralRe: Free library Pin
pophelix3-Oct-10 19:55
memberpophelix3-Oct-10 19:55 
QuestionPoints of interest - fixed? Pin
BaShOr6-Apr-05 14:07
memberBaShOr6-Apr-05 14:07 
AnswerRe: Points of interest - fixed? Pin
Mathew Hall6-Apr-05 15:30
memberMathew Hall6-Apr-05 15:30 
GeneralRe: Points of interest - fixed? Pin
Don Kackman6-Sep-05 15:15
memberDon Kackman6-Sep-05 15:15 
GeneralSideBar hides itself when mouse is over a scrollbar Pin
Peter Kenyon28-Feb-05 18:00
sussPeter Kenyon28-Feb-05 18:00 
GeneralRe: SideBar hides itself when mouse is over a scrollbar Pin
Don Kackman19-Mar-05 16:14
memberDon Kackman19-Mar-05 16:14 
GeneralNelsonWise Pin
yeehoo300017-Feb-05 1:20
memberyeehoo300017-Feb-05 1:20 
GeneralRe: NelsonWise Pin
Don Kackman17-Feb-05 14:04
memberDon Kackman17-Feb-05 14:04 
GeneralAlso, getting rid of graphic artefacts when resizing a ThemeablePanel Pin
dzCepheus29-May-04 14:03
memberdzCepheus29-May-04 14:03 
GeneralRe: Also, getting rid of graphic artefacts when resizing a ThemeablePanel Pin
Don Kackman30-May-04 9:10
memberDon Kackman30-May-04 9:10 
GeneralRe: Also, getting rid of graphic artefacts when resizing a ThemeablePanel Pin
dzCepheus30-May-04 10:20
memberdzCepheus30-May-04 10:20 
GeneralRe: Also, getting rid of graphic artefacts when resizing a ThemeablePanel Pin
Don Kackman30-May-04 10:34
memberDon Kackman30-May-04 10:34 
GeneralRe: Also, getting rid of graphic artefacts when resizing a ThemeablePanel Pin
dzCepheus30-May-04 12:26
memberdzCepheus30-May-04 12:26 
GeneralNamespace for SideBar incorrect Pin
dzCepheus29-May-04 13:53
memberdzCepheus29-May-04 13:53 
GeneralRe: Namespace for SideBar incorrect Pin
Don Kackman30-May-04 9:06
memberDon Kackman30-May-04 9:06 
QuestionHow to use in VB.NET ? Pin
mistert00626-May-04 16:32
membermistert00626-May-04 16:32 
AnswerRe: How to use in VB.NET ? Pin
Don Kackman27-May-04 5:19
memberDon Kackman27-May-04 5:19 
GeneralMultiple Side Bars to Collapse on the Same Side Pin
TaoLi29-Apr-04 13:50
memberTaoLi29-Apr-04 13:50 
GeneralSetWindowTheme Pin
shalnov15-Jan-04 5:48
membershalnov15-Jan-04 5:48 
GeneralColors when using a olive color theme Pin
pgroene5-Jan-04 5:42
memberpgroene5-Jan-04 5:42 
GeneralRe: Colors when using a olive color theme Pin
Don Kackman5-Jan-04 5:53
memberDon Kackman5-Jan-04 5:53 
GeneralXP look on W2K Pin
vikrams31-Aug-03 21:29
membervikrams31-Aug-03 21:29 
GeneralRe: XP look on W2K Pin
Don Kackman1-Sep-03 8:02
memberDon Kackman1-Sep-03 8:02 
GeneralShellStyle.dll Pin
Derek Lakin25-Aug-03 22:12
memberDerek Lakin25-Aug-03 22:12 
GeneralRe: ShellStyle.dll Pin
Don Kackman26-Aug-03 6:29
memberDon Kackman26-Aug-03 6:29 
GeneralRe: ShellStyle.dll Pin
Derek Lakin26-Aug-03 23:29
memberDerek Lakin26-Aug-03 23:29 
GeneralRe: ShellStyle.dll Pin
Don Kackman27-Aug-03 5:25
memberDon Kackman27-Aug-03 5:25 
GeneralRe: ShellStyle.dll Pin
Derek Lakin27-Aug-03 5:33
memberDerek Lakin27-Aug-03 5:33 
GeneralRe: ShellStyle.dll Pin
Creative112-Nov-03 18:06
memberCreative112-Nov-03 18:06 
GeneralRe: ShellStyle.dll Pin
Derek Lakin16-Nov-03 23:22
memberDerek Lakin16-Nov-03 23:22 
GeneralRe: ShellStyle.dll Pin
Creative117-Nov-03 7:28
memberCreative117-Nov-03 7:28 
GeneralRe: ShellStyle.dll Pin
Derek Lakin17-Nov-03 23:36
memberDerek Lakin17-Nov-03 23:36 
GeneralRe: ShellStyle.dll Pin
Daniël Pelsmaeker2-Dec-03 2:09
memberDaniël Pelsmaeker2-Dec-03 2:09 
GeneralRe: ShellStyle.dll Pin
Derek Lakin2-Dec-03 2:17
memberDerek Lakin2-Dec-03 2:17 
GeneralRe: ShellStyle.dll Pin
Daniël Pelsmaeker2-Dec-03 2:21
memberDaniël Pelsmaeker2-Dec-03 2:21 
GeneralRe: ShellStyle.dll Pin
Stephen Lamb16-Oct-05 18:50
memberStephen Lamb16-Oct-05 18:50 
Generalbug Pin
leijtens25-Aug-03 21:10
memberleijtens25-Aug-03 21:10 
GeneralRe: bug Pin
Don Kackman26-Aug-03 5:05
memberDon Kackman26-Aug-03 5:05 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Terms of Use | Mobile
Web04 | 2.8.150506.1 | Last Updated 1 Sep 2003
Article Copyright 2003 by Don Kackman
Everything else Copyright © CodeProject, 1999-2015
Layout: fixed | fluid