Click here to Skip to main content
13,042,166 members (77,505 online)
Click here to Skip to main content
Add your own
alternative version


42 bookmarked
Posted 12 Apr 2004

DateTimePicker appears flat

, 17 May 2005
Rate this:
Please Sign up or sign in to vote.
A simple and easy class that draws the standard DateTimePicker as a flat control.

Sample Image - FlatDateTimePicker.jpg


All the while, we have been using Lumisoft flat controls for our project. However the date picker control supplied does not have support for the time element. I decided to use the standard .NET DateTimePicker control, but the 3D appearance of the control looked really awful in the middle of all the flat controls. After much searching and reading, I couldn't find a readily usable class/control for the purpose that I wanted, and some suggested codes were rather complicated. Based on these information and suggestions by other authors, I came out with this class which is simple and yet functional. It does exactly what I want in a very simple way as well, by using the ControlPaint class supplied in the .NET framework.

Using the Class

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

So instead of doing this:

DateTimePicker dtp = new DateTimePicker();

You will do:

DateTimePicker dtp = new FlatDateTimePicker();

// OR

FlatDateTimerPicker dtp = new FlatDateTimePicker();

That is how simple it is :)

Code Explanation

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

Note that in this method, we need to acquire the actual window DC for the control using WinAPI GetWindowDC and release it later by using ReleaseDC. One main reason of using this over simply creating the Graphics object is because we need the entire DC of the control (bound rectangle) not just the client rectangle, therefore we can paint the border.

protected override void WndProc(ref Message m)
 IntPtr hDC = GetWindowDC(m.HWnd);
 Graphics gdc = Graphics.FromHdc(hDC);
 switch (m.Msg)
  case WM_NC_PAINT:
   SendMessage(this.Handle, WM_ERASEBKGND, hDC, 0);
   SendMessage(this.Handle, WM_PAINT, IntPtr.Zero, 0);

   m.Result = (IntPtr)1; // indicate msg has been processed
  case WM_PAINT: base.WndProc(ref m);
    case  WM_NC_HITTEST:
   base.WndProc(ref m);
   if (DroppedDown)
    this.Invalidate(this.ClientRectangle, false);
   base.WndProc(ref m);
 ReleaseDC(m.HWnd, hDC);

WM_NC_PAINT message is received when the control needs to paint its border. Here I trapped the message and do the border painting myself without calling the base class method, because the base class will try to draw this with a 3D border. I also clear the area prior to the border drawing otherwise it may cause some potential redraw problem when a control/dialog overlays on top such as when a combo box pops up.

WM_PAINT message is received when the control needs to paint portions of its windows. Here we just pass the message to the base class and let the control take care of the drawing (including the display value), but after, we will override the border and the drop down button to ensure that they are flat. 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.

WM_NCHITTEST message is received when you move your mouse around within the control. Many have attempted to write flat controls but were unable to draw the pulldown arrow in flat when the popup appears, because of not trapping this message properly. Every time the pulldown is clicked, the CloseUp or DropDown is called and followed by a redraw which will paint the 3D arrow onto the control; therefore to achieve the flat look, we have to redraw it here. Simply calling Invalidate in this case block will cause flickering, so we will only want to redraw it when the Calendar control actually pops up.

Change Logs

  • 13 April 2004
    • Posted.
  • 22 April 2004
    • Fixed the missing text problem reported.
  • 18 May 2005
    • Fixed flickering problem.
    • DROPDOWNWIDTH value is dynamic now based on the system setting, hence will work well in different screen resolutions.
    • Fixed drop down button redraw problem when mouse is not moved.


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
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.

You may also be interested in...

Comments and Discussions

Questionflat drop-down arrow button? Pin
Kaine2-Aug-10 0:46
memberKaine2-Aug-10 0:46 
GeneralDropdown Icon Pin
Dewayne Dodd6-Apr-09 15:02
memberDewayne Dodd6-Apr-09 15:02 
Generalfine control with one question Pin
thirstyDev2-Dec-08 19:56
memberthirstyDev2-Dec-08 19:56 
GeneralRe: fine control with one question Pin
Fadrian Sudaman3-Dec-08 2:10
memberFadrian Sudaman3-Dec-08 2:10 
GeneralGood work!! Just a small correction on PInvoke declaration Pin
Caio Proiete11-Jul-08 5:27
memberCaio Proiete11-Jul-08 5:27 
GeneralRed Rectangle Pin
diazpablomiguel23-Apr-08 5:22
memberdiazpablomiguel23-Apr-08 5:22 version Pin
MSP129-May-07 22:20
memberMSP129-May-07 22:20 
Here is the equivalent VB version.

Imports System
Imports System.Windows.Forms
Imports System.Drawing
Imports System.Drawing.Drawing2D
Imports System.Runtime.InteropServices
Public class FlatDateTimePicker
  Inherits DateTimePicker
	Private Class ComboInfoHelper
		Private Declare Function GetComboBoxInfo Lib "user32.dll" (hwndCombo As Int32, ByRef info As ComboBoxInfo) As Boolean
		Private Structure RECT 
			public Left    As Int32
			public Top     As Int32
			public Right   As Int32
			public Bottom  As Int32
		End Structure
    Private Structure ComboBoxInfo
      Public cbSize      As Int32
      Public rcItem      As RECT
      Public rcButton    As RECT
      Public stateButton As IntPtr
      Public hwndCombo   As IntPtr
      Public hwndEdit    As IntPtr
      Public hwndList    As IntPtr
    End Structure
    Public Shared Function GetComboDropDownWidth() As Int32
			Dim cb As ComboBox = new ComboBox()
			Dim width As Int32 = GetComboDropDownWidth(cb.Handle)
      Return Width
		End Function
    Public Shared Function GetComboDropDownWidth(ByVal handle As IntPtr) As Int32
      Dim cbi As ComboBoxInfo = New ComboBoxInfo()
      cbi.cbSize = Marshal.SizeOf(cbi)
			GetComboBoxInfo(handle.ToInt32, cbi)
      Dim Width As Int32 = cbi.rcButton.Right - cbi.rcButton.Left
      Return Width
    End Function
	End Class
  Private Declare Function SendMessage Lib "user32.dll" Alias "SendMessageA"(hwnd As Int32, wMsg As Int32, wParam As Int32, lParam As Int32) As Int32
  Private Declare Function GetWindowDC Lib "user32.dll"(hwnd As Int32) As IntPtr
  Private Declare Function ReleaseDC   Lib "user32.dll"(hwnd As Int32, hDC As Int32) As Int32
  Const WM_ERASEBKGND                As Int32   = &H14
  Const WM_PAINT                     As Int32   = &HF
  Const WM_NC_HITTEST                As Int32   = &H84
  Const WM_NC_PAINT                  As Int32   = &H85
  Const WM_PRINTCLIENT               As Int32   = &H318
  Const WM_SETCURSOR                 As Int32   = &H20

  Private BorderPen                  As Pen     = New Pen(Color.Black, 2)
  Private BorderPenControl           As Pen     = New Pen(SystemColors.ControlDark, 2)
  Private DroppedDown                As Boolean = False
  Private InvalidateSince            As Int32   = 0
  Private Shared DropDownButtonWidth As Int32   = 17
	Shared Sub New()
		'2 pixel extra is for the 3D border around the pulldown button on the left and right
		DropDownButtonWidth = ComboInfoHelper.GetComboDropDownWidth() + 2	
	End Sub
  Public Sub New()
    Me.SetStyle(ControlStyles.DoubleBuffer, True)
    Me.SetStyle(ControlStyles.AllPaintingInWmPaint, True)
  End Sub
  Protected Overrides Function IsInputKey(ByVal keyData As System.Windows.Forms.Keys) As Boolean
    If keyData = (Keys.Tab Or Keys.Shift) Then
      Return True
    ElseIf keyData = Keys.Tab Then
      Return True
      Return MyBase.IsInputKey(keyData)
    End If
  End Function
  Protected Overrides Sub OnValueChanged(ByVal eventargs As EventArgs)
  End Sub
  Protected Overrides Sub WndProc(ByRef m As Message)
    Dim hDC As IntPtr = IntPtr.Zero
    Dim gdc As Graphics = Nothing
    Select Case m.Msg
      Case WM_NC_PAINT
        hDC = GetWindowDC(m.HWnd.ToInt32)
        gdc = Graphics.FromHdc(hDC)
        SendMessage(Me.Handle.ToInt32, WM_ERASEBKGND, hDC.ToInt32, 0)
        SendMessage(Me.Handle.ToInt32, WM_PAINT, IntPtr.Zero.ToInt32, 0)
        m.Result = New IntPtr(1)  'Indicate msg has been processed
        ReleaseDC(m.HWnd.ToInt32, hDC.ToInt32)
      Case WM_PAINT
        hDC = GetWindowDC(m.HWnd.ToInt32)
        gdc = Graphics.FromHdc(hDC)
        ReleaseDC(m.HWnd.ToInt32, hDC.ToInt32)
        ' The value 3 is discovered by trial on error, and cover all kinds of scenarios
        ' InvalidateSince < 2 wil have problem if the control is not in focus and dropdown is clicked
        If DroppedDown And (InvalidateSince < 3) Then
          InvalidateSince = InvalidateSince + 1
        End If
      Case Else
    End Select
  End Sub
  Private Sub SendPrintClientMsg()
    'We send this message for the control to redraw the client area
    Dim gClient As Graphics = Me.CreateGraphics()
    Dim ptrClientDC As IntPtr = gClient.GetHdc()
    SendMessage(Me.Handle.ToInt32, WM_PRINTCLIENT, ptrClientDC.ToInt32, 0)
  End Sub
  Private Sub OverrideDropDown(ByVal g As Graphics)
    If Not Me.ShowUpDown Then
      Dim rect As Rectangle = New Rectangle(Me.Width - DropDownButtonWidth, 0, DropDownButtonWidth, Me.Height)
      ControlPaint.DrawComboButton(g, rect, ButtonState.Flat)
    End If
  End Sub
  Private Sub OverrideControlBorder(ByVal g As Graphics)
    If Not Me.Focused Or Not Me.Enabled Then
      g.DrawRectangle(BorderPenControl, New Rectangle(0, 0, Me.Width, Me.Height))
      g.DrawRectangle(BorderPen, New Rectangle(0, 0, Me.Width, Me.Height))
    End If
  End Sub
  Protected Overrides Sub OnDropDown(ByVal eventargs As EventArgs)
    InvalidateSince = 0
    DroppedDown = True
  End Sub
  Protected Overrides Sub OnCloseUp(ByVal eventargs As EventArgs)
    DroppedDown = False
  End Sub
  Protected Overrides Sub OnLostFocus(ByVal e As System.EventArgs)
  End Sub
  Protected Overrides Sub OnGotFocus(ByVal e As System.EventArgs)
  End Sub
  Protected Overrides Sub OnResize(ByVal e As EventArgs)
  End Sub
End Class

Malcolm Powell
GeneralRe: version Pin
MSP129-May-07 22:35
memberMSP129-May-07 22:35 
GeneralRe: version Pin
S. Töpfer22-Feb-10 1:20
memberS. Töpfer22-Feb-10 1:20 
GeneralDateTimePicker with Popup FlatStyle support Pin
vachaun4-May-07 10:30
membervachaun4-May-07 10:30 
GeneralRe: DateTimePicker with Popup FlatStyle support Pin
Fadrian Sudaman5-May-07 15:00
memberFadrian Sudaman5-May-07 15:00 
GeneralRe: DateTimePicker with Popup FlatStyle support [modified] Pin
vachaun6-May-07 10:33
membervachaun6-May-07 10:33 
GeneralRe: DateTimePicker with Popup FlatStyle support Pin
Fadrian Sudaman9-May-07 2:57
memberFadrian Sudaman9-May-07 2:57 
GeneralRe: DateTimePicker with Popup FlatStyle support Pin
vachaun10-May-07 5:14
membervachaun10-May-07 5:14 
GeneralRe: DateTimePicker with Popup FlatStyle support Pin
Fadrian Sudaman10-May-07 13:22
memberFadrian Sudaman10-May-07 13:22 
GeneralRe: DateTimePicker with Popup FlatStyle support Pin
vachaun11-May-07 2:25
membervachaun11-May-07 2:25 version Pin
rgf2119-Mar-07 1:55
memberrgf2119-Mar-07 1:55 
AnswerRe: version Pin
Fadrian Sudaman9-May-07 3:01
memberFadrian Sudaman9-May-07 3:01 
GeneralRe: version Pin
MSP129-May-07 22:40
memberMSP129-May-07 22:40 
QuestionPInvokeStackInbalanceException raised Pin
Jacek Osiecki16-Jan-07 2:12
memberJacek Osiecki16-Jan-07 2:12 
AnswerRe: PInvokeStackInbalanceException raised Pin
Fadrian Sudaman16-Jan-07 13:00
memberFadrian Sudaman16-Jan-07 13:00 
GeneralRe: PInvokeStackInbalanceException raised Pin
Jacek Osiecki16-Jan-07 23:38
memberJacek Osiecki16-Jan-07 23:38 
GeneralTransparencyKey problem Pin
AlexDias3-Oct-06 8:12
memberAlexDias3-Oct-06 8:12 
GeneralRe: TransparencyKey problem Pin
Fadrian Sudaman4-Oct-06 3:25
memberFadrian Sudaman4-Oct-06 3:25 
GeneralTime select didn not appear Pin
jcui@activplant.com13-Jun-05 8:12
memberjcui@activplant.com13-Jun-05 8:12 
GeneralRe: Time select didn not appear Pin
Fadrian Sudaman15-Jun-05 0:30
memberFadrian Sudaman15-Jun-05 0:30 
GeneralNice but it's not all flat Pin
zxcvasda9-Jun-05 18:59
memberzxcvasda9-Jun-05 18:59 
GeneralRe: Nice but it's not all flat Pin
Fadrian Sudaman9-Jun-05 19:25
memberFadrian Sudaman9-Jun-05 19:25 
GeneralNice control, two questions though. Pin
JazzJackRabbit13-May-05 3:31
memberJazzJackRabbit13-May-05 3:31 
GeneralRe: Nice control, two questions though. Pin
Fadrian Sudaman14-May-05 17:28
memberFadrian Sudaman14-May-05 17:28 
GeneralButton still flickers Pin
Duc de Belfort9-Mar-05 2:55
memberDuc de Belfort9-Mar-05 2:55 
GeneralRe: Button still flickers Pin
Duc de Belfort9-Mar-05 3:52
memberDuc de Belfort9-Mar-05 3:52 
GeneralRe: Button still flickers Pin
Fadrian Sudaman10-Mar-05 12:31
memberFadrian Sudaman10-Mar-05 12:31 
GeneralRe: Button still flickers Pin
JazzJackRabbit13-May-05 4:41
memberJazzJackRabbit13-May-05 4:41 
GeneralRe: Button still flickers Pin
Fadrian Sudaman16-May-05 6:04
memberFadrian Sudaman16-May-05 6:04 
GeneralRe: Button still flickers Pin
JazzJackRabbit16-May-05 16:55
memberJazzJackRabbit16-May-05 16:55 
GeneralRe: Button still flickers Pin
Fadrian Sudaman17-May-05 3:38
memberFadrian Sudaman17-May-05 3:38 
GeneralAdd highlight color property Pin
nguyenquanghung7-Nov-04 16:37
membernguyenquanghung7-Nov-04 16:37 
GeneralRe: Add highlight color property Pin
Fadrian Sudaman9-Nov-04 18:42
sussFadrian Sudaman9-Nov-04 18:42 
QuestionUndesidered Pixel? Pin
Jordi Corominas4-Nov-04 22:33
memberJordi Corominas4-Nov-04 22:33 
AnswerRe: Undesidered Pixel? Pin
Fadrian Sudaman5-Nov-04 1:39
sussFadrian Sudaman5-Nov-04 1:39 
GeneralRe: Undesidered Pixel? Pin
Jordi Corominas5-Nov-04 2:17
memberJordi Corominas5-Nov-04 2:17 
GeneralRe: Undesidered Pixel? Pin
Fadrian Sudaman7-Nov-04 11:58
memberFadrian Sudaman7-Nov-04 11:58 
GeneralRe: Undesidered Pixel? Pin
Fadrian Sudaman9-Nov-04 18:34
sussFadrian Sudaman9-Nov-04 18:34 
GeneralRe: Undesidered Pixel? Pin
JazzJackRabbit16-May-05 4:10
memberJazzJackRabbit16-May-05 4:10 
GeneralDrop-down bug Pin
smako7-Aug-04 9:41
membersmako7-Aug-04 9:41 
GeneralNeed sample of how to use Pin
rarmstrong222230-Jun-04 11:31
memberrarmstrong222230-Jun-04 11:31 
GeneralRe: Need sample of how to use Pin
Fadrian Sudaman1-Jul-04 16:26
memberFadrian Sudaman1-Jul-04 16:26 
GeneralSome comments... Pin
Victor Boctor18-May-04 19:57
memberVictor Boctor18-May-04 19:57 
GeneralRe: Some comments... Pin
Fadrian Sudaman24-May-04 20:51
memberFadrian Sudaman24-May-04 20:51 

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

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

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