Using DateTimePicker and Custom Format
Today we ran into a nasty problem with DateTimePickerFormat.Custom. We allow the user to input a month/date with a DateTimePicker as following (nothing fancy)
private void Form1_Load(object sender, EventArgs e)
{
this.dateTimePicker1.Value = new DateTime(2007, 8, 31);
this.dateTimePicker1.Format = DateTimePickerFormat.Custom;
this.dateTimePicker1.CustomFormat = "MM/yyyy";
}
Now, change to 09/2007 and notice that you get an Exception, because the control tries to create an unrepresentable new DateTime(2007, 8+1, 31). Thus, if you’re going to use the DateTimePicker for MM/yyyy input make sure to set it’s value to a DateTimeTime with a day component that exists for all months/years (thus a value between 1 and 28).
Addendum: As usual, super moderator and MVP Hans Passant provided a nice workaround for the problem:)
public class MonthPicker : DateTimePicker
{
public MonthPicker()
{
this.Format = DateTimePickerFormat.Custom;
this.CustomFormat = "MM/yyyy";
DateTime now = DateTime.Now;
this.Value = new DateTime(now.Year, now.Month, 1);
}
protected override void WndProc(ref Message m)
{
if (m.Msg == 0x204e)
{
NMHDR hdr = (NMHDR)m.GetLParam(typeof(NMHDR));
if (hdr.code == -759)
{
NMDATETIMECHANGE dt = (NMDATETIMECHANGE)m.GetLParam(typeof(NMDATETIMECHANGE));
this.Value = new DateTime(dt.st.wYear, dt.st.wMonth, 1);
return;
}
}
base.WndProc(ref m);
}
// P/Invoke declarations
[StructLayout(LayoutKind.Sequential)]
private struct NMHDR
{
public IntPtr hWnd;
public IntPtr id;
public int code;
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
private class NMDATETIMECHANGE
{
public NMHDR nmhdr;
public int dwFlags;
public SYSTEMTIME st;
}
[StructLayout(LayoutKind.Sequential)]
private class SYSTEMTIME
{
public short wYear;
public short wMonth;
public short wDayOfWeek;
public short wDay;
public short wHour;
public short wMinute;
public short wSecond;
public short wMilliseconds;
}
}