Click here to Skip to main content
Click here to Skip to main content

Making Standard ComboBox appear flat

By , 18 May 2005
 

Sample Image - flatcombo.jpg

Introduction

Many flat combobox controls out there are not based on the standard ComboBox control that is supplied by .NET, instead they have their own interfaces and requires a customized type of ComboBoxItem when inserting into the Items container. If you already have code written based on the standard .NET ComboBox, changing to the flat look may also require you to modify your codes. I have personally experienced that as a problem, and someone else has brought that up as a problem as well in my recent article DateTimePicker appears Flat. Many of the information provided here may appear in the DateTimePicker appears Flat article already, or maybe explained better in there, so please check it out.

Using the Class

This class inherits from ComboBox, therefore you can use it in exactly the same way as the ComboBox control or even as a replacement.

So instead of doing this:

ComboBox  cmb = new ComboBox();

You will do:

ComboBox cmb = new FlatComboBox();
// OR
FlatComboBox cmb = new FlatComboBox();

That is how simple it is :)

Code Explanation

To achieve the flat look for the control, I have to override the WndProc method, which is the method that processes through all the window messages for this control. We are particularly interested with WM_NC_PAINT and WM_PAINT messages.

IntPtr hDC = GetWindowDC(this.Handle);

Graphics gdc = Graphics.FromHdc(hDC);

switch (m.Msg)

{
    case WM_NC_PAINT: 
        SendMessage(this.Handle, WM_ERASEBKGND, hDC, 0);
        SendPrintClientMsg(); // send to draw client area
        PaintFlatControlBorder(this, gdc);
        m.Result = (IntPtr) 1; // indicate msg has been processed 
        break;
    case WM_PAINT: 
        base.WndProc(ref m);
        // flatten the border area again
        Pen p = new Pen((this.Enabled? BackColor:SystemColors.Control), 2); 
        gdc.DrawRectangle(p, new Rectangle(2, 2, this.Width-3, this.Height-3));
        PaintFlatDropDown(this, gdc);
        PaintFlatControlBorder(this, gdc);
        break;
    default:
        base.WndProc(ref m);
        break;

}

ReleaseDC(m.HWnd, hDC);

gdc.Dispose(); 

}

WM_NC_PAINT message is received when the control needs to paint its border. Here I trapped the message and send WM_PRINTCLIENT message so that the ComboBox will draw its client area properly, then followed by drawing a flat border around it.

WM_PAINT message is received when the control needs to paint portion of its windows. ComboBox internally embeds a textbox and will draw the textbox with 3D border. A quick way to achieve the flat look is to paint a rectangle overlaying the 3D border of the textbox, therefore it will appear flat. We then paint the flat dropdown and border over it. Overriding the border is optional here, but I did it for the user experience where if the control is in focus, it will have a black line border or otherwise none.

Limitation

Currently, this FlatComboBox does not draw with ComboBox.Simple style. When this style is set for the ComboBox object, this class will let the base class perform the standard drawing.

History

  • 18 May 2005
    • DROPDOWNWIDTH value is dynamic now based on the system setting hence will work well in different screen resolutions.
    • Only acquires and creates window DC when necessary.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here

About the Author

Fadrian Sudaman
Architect SMS Management and Technology
Australia Australia
Member
Fadrian Sudaman is an experienced IT professional who has worked with .NET technology since the early beta. His background stems from a strong C/C++ development experience in building large commercial applications and great appreciation for best practice and modern approaches for building quality software. Currently, Fadrian works as a senior consultant specialises in .NET technology involved in variety of roles including project management, solution architecture, presales and application development. Fadrian is also completing his PhD part time at Monash University, Australia.

Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board.
Search this forum  
    Spacing  Noise  Layout  Per page   
GeneralFlickeringmemberMotero16 Feb '11 - 22:31 
I discovered that the control is flickering multiple times if you mouse over its border. Does anyone know a solution to this?
GeneralRe: Flickeringmembervalefior17 Jul '12 - 23:45 
Try to discard both the WM_MOUSEFIRST and WM_MOUSELEAVE events:
 
switch (m.Msg)
{
    case WM_MOUSEFIRST: // 0x0200
    case WM_MOUSELEAVE: // 0x02A3
        m.Result = (IntPtr)1;
        break;

Generalthanksmembergavin.r4 Feb '09 - 5:01 
Smile | :)
GeneralIn VS2008/VistamvpJohn Simmons / outlaw programmer25 Nov '08 - 8:12 
In the designer, the control paints as expected. However, when the application is actually run, the control has an inner white border (including one that separates the down-arrow button with the control's text area).
 

"Why don't you tie a kerosene-soaked rag around your ankles so the ants won't climb up and eat your candy ass..." - Dale Earnhardt, 1997
-----
"...the staggering layers of obscenity in your statement make it a work of art on so many levels." - Jason Jystad, 10/26/2001

GeneralRe: In VS2008/VistamemberFadrian Sudaman3 Dec '08 - 1:53 
I haven't got the environment to try that out and fixing it. Hopefully someone else can give it a go.
GeneralRe: In VS2008/Vistamemberakerd1 Feb '13 - 22:37 
Yes, same problem here with Visual Studio 2010 and Windows 8.
 
Here it is a screenshot:
 
http://i.imgur.com/lk4aW4m.jpg[^]
QuestionA call to PInvoke function ErrormemberIs-sanga12 Jun '08 - 0:06 
can any one please help on this issue that was found when I'm using C# .NET 2005 and when i click on the control it appears like this
 
PInvokeStackImbalance was detected
Message: A call to PInvoke function 'SSLib!SSLib.UserControls.ExtendedComboBox::SendMessage' has unbalanced the stack. This is likely because the managed PInvoke signature does not match the unmanaged target signature. Check that the calling convention and parameters of the PInvoke signature match the target unmanaged signature.
 

Isara
AnswerRe: A call to PInvoke function ErrormemberFadrian Sudaman3 Dec '08 - 1:17 
Didn't remember seeing this post on my email and just realize it now. Hope you have resolved this issue by now, if not try this.
 
Try changing the declaration to this
[DllImport("user32.dll", EntryPoint = "SendMessageA")]
private static extern int SendMessage(IntPtr hwnd, int wMsg, IntPtr wParam, IntPtr lParam);
 
And when invoking it, replace the last parameter from "0" to IntPtr.Zero
GeneralGet the DropDawnList handle (graphics)memberElmaho11 Apr '08 - 8:28 
great work and thanks for this article.
my wish is to customise the drop dawn list, not the items but the border and the backcolor of this.
 
thanks again
GeneralEnable = falsememberjorge.ramos21 Nov '07 - 8:54 
Hi, first of all I wanna thank you for this article.
I'm having a little problem when the control is disabled because an extra border is drawn, but when it is enabled again, it draws correctly.
I've tried to avoid the drawing of the rectangle when the control is disable, but nothing happens.
Any suggestions would be appreciated.
Thanks.
 
PD. sorry for my english Smile | :)

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

Permalink | Advertise | Privacy | Mobile
Web03 | 2.6.130523.1 | Last Updated 18 May 2005
Article Copyright 2004 by Fadrian Sudaman
Everything else Copyright © CodeProject, 1999-2013
Terms of Use
Layout: fixed | fluid