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();
FlatDateTimerPicker dtp = new FlatDateTimePicker();
That is how simple it is :)
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
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);
SendMessage(this.Handle, WM_ERASEBKGND, hDC, 0);
SendMessage(this.Handle, WM_PAINT, IntPtr.Zero, 0);
m.Result = (IntPtr)1;
case WM_PAINT: base.WndProc(ref m);
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
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.
- 13 April 2004
- 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.