可以为空值、可以删除显示日期的DateTimePicker
.Net的DateTimePicker没有提供空白显示的功能,一旦选择了日期,也不可删除而显示空白,且在非Windows XP主体环境下也没有Flat显示功能,直接放在界面上还真不太美观,于是着手改造了一下。
如果想出时显示时日期为空,则设置Format属性为Custom,设置CustomFormat属性为空格" "即可:
using System;
using System.Windows.Forms;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Runtime.InteropServices;
using Srims.UI.Controls;
namespace DrawFlat
{
[ToolboxBitmap(typeof(System.Windows.Forms.DateTimePicker))]
public class FlatDateTimePicker: DateTimePicker
{
ComboInfoHelper
[DllImport("user32.dll", EntryPoint="SendMessageA")]
private static extern int SendMessage (IntPtr hwnd, int wMsg, IntPtr wParam, int lParam);
[DllImport("user32")]
private static extern IntPtr GetWindowDC (IntPtr hWnd );
[DllImport("user32")]
private static extern int ReleaseDC(IntPtr hWnd, IntPtr hDC );
const int WM_ERASEBKGND = 0x14;
const int WM_PAINT = 0xF;
const int WM_NC_HITTEST = 0x84;
const int WM_NC_PAINT = 0x85;
const int WM_PRINTCLIENT = 0x318;
const int WM_SETCURSOR = 0x20;
private Pen BorderPen = new Pen(Color.Black, 2);
private Pen BorderPenControl = new Pen(SystemColors.ControlDark, 2);
private bool DroppedDown = false;
private int InvalidateSince = 0;
private static int DropDownButtonWidth = 17;
static FlatDateTimePicker()
{
// 2 pixel extra is for the 3D border around the pulldown button on the left and right
DropDownButtonWidth = ComboInfoHelper.GetComboDropDownWidth()+2 ;
}
public FlatDateTimePicker()
: base()
{
this.SetStyle(ControlStyles.DoubleBuffer, true);
//this.SetStyle(ControlStyles.AllPaintingInWmPaint, true);
}
protected override void OnValueChanged(EventArgs eventargs)
{
base.OnValueChanged (eventargs);
this.Invalidate();
}
protected override void WndProc(ref Message m)
{
//IntPtr hDC = IntPtr.Zero;
//Graphics gdc = null;
//switch (m.Msg)
//{
// case WM_NC_PAINT:
// hDC = GetWindowDC(m.HWnd);
// gdc = Graphics.FromHdc(hDC);
// SendMessage(this.Handle, WM_ERASEBKGND, hDC, 0);
// SendPrintClientMsg();
// SendMessage(this.Handle, WM_PAINT, IntPtr.Zero, 0);
// OverrideControlBorder(gdc);
// //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);
// hDC = GetWindowDC(m.HWnd);
// gdc = Graphics.FromHdc(hDC);
// OverrideDropDown(gdc);
// OverrideControlBorder(gdc);
// //PaintFlatControlBorder(this, gdc);
// ReleaseDC(m.HWnd, hDC);
// gdc.Dispose();
// break;
// /*
// // We don't need this anymore, handle by WM_SETCURSOR
// case WM_NC_HITTEST:
// base.WndProc(ref m);
// if (DroppedDown)
// {
// OverrideDropDown(gdc);
// OverrideControlBorder(gdc);
// }
// break;
// */
// //case WM_SETCURSOR:
// // base.WndProc(ref m);
// // // 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 && InvalidateSince < 3)
// // {
// // Invalidate();
// // InvalidateSince++;
// // }
// // break;
// default:
// base.WndProc(ref m);
// break;
//}
IntPtr hDC = GetWindowDC(m.HWnd);
Graphics gdc = Graphics.FromHdc(hDC);
switch (m.Msg)
{
case WM_NC_PAINT:
SendMessage(this.Handle, WM_ERASEBKGND, hDC, 0);
SendPrintClientMsg();
SendMessage(this.Handle, WM_PAINT, IntPtr.Zero, 0);
OverrideControlBorder(gdc);
m.Result = (IntPtr)1; // indicate msg has been processed
break;
case WM_PAINT: base.WndProc(ref m);
OverrideControlBorder(gdc);
OverrideDropDown(gdc);
break;
case WM_NC_HITTEST:
base.WndProc(ref m);
if (DroppedDown)
this.Invalidate(this.ClientRectangle, false);
break;
default:
base.WndProc(ref m);
break;
}
ReleaseDC(m.HWnd, hDC);
gdc.Dispose();
}
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);
}
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();
}
public void SetText(string text)
{
if (text != "")
{
this.Format = DateTimePickerFormat.Long;
this.Text = text;
}
else
{
this.Format = DateTimePickerFormat.Custom;
}
}
private void OverrideDropDown(Graphics g)
{
if (!this.ShowUpDown)
{
Rectangle rect = new Rectangle(this.Width-DropDownButtonWidth, 0, DropDownButtonWidth, this.Height);
ControlPaint.DrawComboButton(g, rect, ButtonState.Flat);
}
}
private void OverrideControlBorder(Graphics g)
{
//this.Width = this.Width + 4;
if (this.Focused == false || this.Enabled == false )
g.DrawRectangle(BorderPenControl, new Rectangle(0, 0, this.Width, this.Height));
else
g.DrawRectangle(BorderPen, new Rectangle(0, 0, this.Width, this.Height));
}
protected override void OnKeyUp(KeyEventArgs e)
{
if (e.KeyCode == Keys.Back || e.KeyCode == Keys.Delete)
{
this.Format = DateTimePickerFormat.Custom;
this.CustomFormat = " ";
// OnValueChanged(EventArgs.Empty);
}
base.OnKeyUp(e);
}
protected override void OnDropDown(EventArgs eventargs)
{
InvalidateSince = 0;
DroppedDown = true;
base.OnDropDown (eventargs);
}
protected override void OnCloseUp(EventArgs eventargs)
{
DroppedDown = false;
this.Format = DateTimePickerFormat.Long;
base.OnCloseUp (eventargs);
}
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();
}
}
}
using System.Windows.Forms;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Runtime.InteropServices;
using Srims.UI.Controls;
namespace DrawFlat
{
[ToolboxBitmap(typeof(System.Windows.Forms.DateTimePicker))]
public class FlatDateTimePicker: DateTimePicker
{
ComboInfoHelper
[DllImport("user32.dll", EntryPoint="SendMessageA")]
private static extern int SendMessage (IntPtr hwnd, int wMsg, IntPtr wParam, int lParam);
[DllImport("user32")]
private static extern IntPtr GetWindowDC (IntPtr hWnd );
[DllImport("user32")]
private static extern int ReleaseDC(IntPtr hWnd, IntPtr hDC );
const int WM_ERASEBKGND = 0x14;
const int WM_PAINT = 0xF;
const int WM_NC_HITTEST = 0x84;
const int WM_NC_PAINT = 0x85;
const int WM_PRINTCLIENT = 0x318;
const int WM_SETCURSOR = 0x20;
private Pen BorderPen = new Pen(Color.Black, 2);
private Pen BorderPenControl = new Pen(SystemColors.ControlDark, 2);
private bool DroppedDown = false;
private int InvalidateSince = 0;
private static int DropDownButtonWidth = 17;
static FlatDateTimePicker()
{
// 2 pixel extra is for the 3D border around the pulldown button on the left and right
DropDownButtonWidth = ComboInfoHelper.GetComboDropDownWidth()+2 ;
}
public FlatDateTimePicker()
: base()
{
this.SetStyle(ControlStyles.DoubleBuffer, true);
//this.SetStyle(ControlStyles.AllPaintingInWmPaint, true);
}
protected override void OnValueChanged(EventArgs eventargs)
{
base.OnValueChanged (eventargs);
this.Invalidate();
}
protected override void WndProc(ref Message m)
{
//IntPtr hDC = IntPtr.Zero;
//Graphics gdc = null;
//switch (m.Msg)
//{
// case WM_NC_PAINT:
// hDC = GetWindowDC(m.HWnd);
// gdc = Graphics.FromHdc(hDC);
// SendMessage(this.Handle, WM_ERASEBKGND, hDC, 0);
// SendPrintClientMsg();
// SendMessage(this.Handle, WM_PAINT, IntPtr.Zero, 0);
// OverrideControlBorder(gdc);
// //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);
// hDC = GetWindowDC(m.HWnd);
// gdc = Graphics.FromHdc(hDC);
// OverrideDropDown(gdc);
// OverrideControlBorder(gdc);
// //PaintFlatControlBorder(this, gdc);
// ReleaseDC(m.HWnd, hDC);
// gdc.Dispose();
// break;
// /*
// // We don't need this anymore, handle by WM_SETCURSOR
// case WM_NC_HITTEST:
// base.WndProc(ref m);
// if (DroppedDown)
// {
// OverrideDropDown(gdc);
// OverrideControlBorder(gdc);
// }
// break;
// */
// //case WM_SETCURSOR:
// // base.WndProc(ref m);
// // // 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 && InvalidateSince < 3)
// // {
// // Invalidate();
// // InvalidateSince++;
// // }
// // break;
// default:
// base.WndProc(ref m);
// break;
//}
IntPtr hDC = GetWindowDC(m.HWnd);
Graphics gdc = Graphics.FromHdc(hDC);
switch (m.Msg)
{
case WM_NC_PAINT:
SendMessage(this.Handle, WM_ERASEBKGND, hDC, 0);
SendPrintClientMsg();
SendMessage(this.Handle, WM_PAINT, IntPtr.Zero, 0);
OverrideControlBorder(gdc);
m.Result = (IntPtr)1; // indicate msg has been processed
break;
case WM_PAINT: base.WndProc(ref m);
OverrideControlBorder(gdc);
OverrideDropDown(gdc);
break;
case WM_NC_HITTEST:
base.WndProc(ref m);
if (DroppedDown)
this.Invalidate(this.ClientRectangle, false);
break;
default:
base.WndProc(ref m);
break;
}
ReleaseDC(m.HWnd, hDC);
gdc.Dispose();
}
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);
}
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();
}
public void SetText(string text)
{
if (text != "")
{
this.Format = DateTimePickerFormat.Long;
this.Text = text;
}
else
{
this.Format = DateTimePickerFormat.Custom;
}
}
private void OverrideDropDown(Graphics g)
{
if (!this.ShowUpDown)
{
Rectangle rect = new Rectangle(this.Width-DropDownButtonWidth, 0, DropDownButtonWidth, this.Height);
ControlPaint.DrawComboButton(g, rect, ButtonState.Flat);
}
}
private void OverrideControlBorder(Graphics g)
{
//this.Width = this.Width + 4;
if (this.Focused == false || this.Enabled == false )
g.DrawRectangle(BorderPenControl, new Rectangle(0, 0, this.Width, this.Height));
else
g.DrawRectangle(BorderPen, new Rectangle(0, 0, this.Width, this.Height));
}
protected override void OnKeyUp(KeyEventArgs e)
{
if (e.KeyCode == Keys.Back || e.KeyCode == Keys.Delete)
{
this.Format = DateTimePickerFormat.Custom;
this.CustomFormat = " ";
// OnValueChanged(EventArgs.Empty);
}
base.OnKeyUp(e);
}
protected override void OnDropDown(EventArgs eventargs)
{
InvalidateSince = 0;
DroppedDown = true;
base.OnDropDown (eventargs);
}
protected override void OnCloseUp(EventArgs eventargs)
{
DroppedDown = false;
this.Format = DateTimePickerFormat.Long;
base.OnCloseUp (eventargs);
}
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();
}
}
}