Click here to Skip to main content
15,893,401 members
Articles / Programming Languages / C#

Making Standard ComboBox appear flat

Rate me:
Please Sign up or sign in to vote.
4.78/5 (45 votes)
18 May 20052 min read 384.4K   5.1K   74  
A simple and easy class that draws the standard ComboBox as flat control.
using System;
using System.Windows.Forms;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Runtime.InteropServices;

namespace DrawFlat
{
	[ToolboxBitmap(typeof(System.Windows.Forms.ComboBox))]
	public class FlatComboBox: ComboBox
	{	
		#region ComboInfoHelper
		internal class ComboInfoHelper
		{
			[DllImport("user32")] 
			private static extern bool GetComboBoxInfo(IntPtr hwndCombo, ref ComboBoxInfo info);

			#region RECT struct
			[StructLayout(LayoutKind.Sequential)]
				private struct RECT 
			{
				public int Left;
				public int Top;
				public int Right;
				public int Bottom;
			}
			#endregion

			#region ComboBoxInfo Struct
			[StructLayout(LayoutKind.Sequential)]
				private struct ComboBoxInfo 
			{
				public int cbSize;
				public RECT rcItem;
				public RECT rcButton;
				public IntPtr stateButton;
				public IntPtr hwndCombo;
				public IntPtr hwndEdit;
				public IntPtr hwndList;
			}
			#endregion

			public static int GetComboDropDownWidth()
			{
				ComboBox cb = new ComboBox();
				int width = GetComboDropDownWidth(cb.Handle);
				cb.Dispose();
				return width;
			}
			public static int GetComboDropDownWidth(IntPtr handle)
			{
				ComboBoxInfo cbi = new ComboBoxInfo();
				cbi.cbSize = Marshal.SizeOf(cbi);
				GetComboBoxInfo(handle, ref cbi);
				int width = cbi.rcButton.Right - cbi.rcButton.Left;
				return width;
			}
		}
		#endregion

		public const int WM_ERASEBKGND = 0x14;
		public const int WM_PAINT = 0xF;
		public const int WM_NC_PAINT = 0x85;
		public const int WM_PRINTCLIENT = 0x318;
		private static int DropDownButtonWidth = 17;

		[DllImport("user32.dll", EntryPoint="SendMessageA")]
		public static extern int SendMessage (IntPtr hwnd, int wMsg, IntPtr wParam, object lParam);

		[DllImport("user32")]
		public static extern IntPtr GetWindowDC (IntPtr hWnd );

		[DllImport("user32")]
		public static extern int ReleaseDC(IntPtr hWnd, IntPtr hDC );

		static FlatComboBox()
		{
			DropDownButtonWidth = ComboInfoHelper.GetComboDropDownWidth() + 2;
		}

        public FlatComboBox()
			: base()
		{
			this.SetStyle(ControlStyles.DoubleBuffer, true);
		}

		protected override void OnSelectedValueChanged(EventArgs e)
		{
			base.OnSelectedValueChanged (e);
			this.Invalidate();
		}

		protected override void WndProc(ref Message m)
		{
			if (this.DropDownStyle == ComboBoxStyle.Simple)
			{
				base.WndProc(ref m);
				return;
			}

			IntPtr hDC = IntPtr.Zero;
			Graphics gdc = null;
			switch (m.Msg)
			{
				case WM_NC_PAINT:	
					hDC = GetWindowDC(this.Handle);
					gdc = Graphics.FromHdc(hDC);
					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			
					ReleaseDC(m.HWnd, hDC);
					gdc.Dispose();	

					break;
				case WM_PAINT:	
					base.WndProc(ref m);
					// flatten the border area again
					hDC = GetWindowDC(this.Handle);
					gdc = Graphics.FromHdc(hDC);
					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);
					ReleaseDC(m.HWnd, hDC);
					gdc.Dispose();	

					break;
				default:
					base.WndProc(ref m);
					break;
			}
		}
		private void SendPrintClientMsg()
		{
			// We send this message for the control to redraw the client area
			Graphics gClient = this.CreateGraphics();
			IntPtr ptrClientDC = gClient.GetHdc();
			SendMessage(this.Handle, WM_PRINTCLIENT, ptrClientDC, 0);
			gClient.ReleaseHdc(ptrClientDC);
			gClient.Dispose();
		}

		private void PaintFlatControlBorder(Control ctrl, Graphics g)
		{
			Rectangle rect = new Rectangle(0, 0, ctrl.Width, ctrl.Height);
			if (ctrl.Focused == false || ctrl.Enabled == false )
				ControlPaint.DrawBorder(g, rect, SystemColors.ControlDark, ButtonBorderStyle.Solid);
			else
				ControlPaint.DrawBorder(g, rect, Color.Black, ButtonBorderStyle.Solid);
		}
		public static void PaintFlatDropDown(Control ctrl, Graphics g)
		{
			Rectangle rect = new Rectangle(ctrl.Width-DropDownButtonWidth, 0, DropDownButtonWidth, ctrl.Height);
			ControlPaint.DrawComboButton(g, rect, ButtonState.Flat);
		}

		protected override void OnLostFocus(System.EventArgs e)
		{
			base.OnLostFocus(e);
			this.Invalidate();
		}

		protected override void OnGotFocus(System.EventArgs e)
		{
			base.OnGotFocus(e);
			this.Invalidate();
		}		
		protected override void OnResize(EventArgs e)
		{
			base.OnResize (e);
			this.Invalidate();
		}

	}
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

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


Written By
Architect SMS Management and Technology
Australia Australia
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.

Comments and Discussions