18
Binding b = new Binding( "Value", person, "BdayNullable", true );
dtBirthdayNullable.DataBindings.Add( b );
b.Format += new ConvertEventHandler( dtBirthdayNullable_Format );

b.Parse += new ConvertEventHandler( dtBirthdayNullable_Parse );

void dtBirthdayNullable_Format( object sender, ConvertEventArgs e )
{
    // e.Value is the object value, we format it to be what we want to show up in the control

    Binding b = sender as Binding;
    if ( b != null )
    {
        DateTimePicker dtp = (b.Control as DateTimePicker);
        if ( dtp != null )
        {
            if ( e.Value == DBvalue.value )
            {
                dtp.ShowCheckBox = true;
                dtp.Checked = false;

                // have to set e.Value to SOMETHING, since it's coming in as NULL
                // if i set to DateTime.Today, and that's DIFFERENT than the control's current 
                // value, then it triggers a CHANGE to the value, which CHECKS the box (not ok)
                // the trick - set e.Value to whatever value the control currently has.  
                // This does NOT cause a CHANGE, and the checkbox stays OFF.
                e.Value = dtp.Value;    
            }
            else
            {
                dtp.ShowCheckBox = true;
                dtp.Checked = true;
                // leave e.Value unchanged - it's not null, so the DTP is fine with it.
            }
        }
    }
}
void dtBirthdayNullable_Parse( object sender, ConvertEventArgs e )
{
    // e.value is the formatted value coming from the control.  
    // we change it to be the value we want to stuff in the object.

    Binding b = sender as Binding;
    if ( b != null )
    {
        DateTimePicker dtp = (b.Control as DateTimePicker);
        if ( dtp != null )
        {
            if ( dtp.Checked == false )
            {
                dtp.ShowCheckBox = true;
                dtp.Checked = false;
                e.Value = DBvalue.Value
            }
            else
            {
                DateTime val = Convert.ToDateTime( e.Value );
                e.Value =val;
            }
        }
    }
}

EDIT

i found a good solution here

http://blogs.interknowlogy.com/danhanan/archive/2007/01/21/10847.aspx

another perfect solution here

http://www.mofeel.net/70-microsoft-public-dotnet-framework-windowsforms/8806.aspx

Aaron W.
  • 9,254
  • 2
  • 34
  • 45
shmandor
  • 881
  • 3
  • 14
  • 22
  • I know this is an old question, but you should consider posting those two links as an answer. They perfectly address the problem of needing to bind nullable database fields to a DateTimePicker. – edsobo Jan 17 '13 at 20:33
  • 2
    possible duplicate of [DateTimePicker Null Value (.NET)](http://stackoverflow.com/questions/284364/datetimepicker-null-value-net) – bluish Nov 13 '13 at 08:38
  • First link did the trick for me – Mario Vázquez Nov 15 '18 at 17:38

6 Answers6

28

DateTimePickers can't be set to null because DateTime can't be null, but you can set them to DateTime.MinValue which is the default value for an uninitialized DateTime. And then you just check if the dtp.Value = DateTime.MinValue and if so, treat it as null.

However, if you want to really distinguish when no value has been selected, the easiest way is to set DateTimePicker.ShowCheckBox to true, and then you check dtp.Checked and if it's true, you read the value, otherwise you treat it as a null.

Hans Olsson
  • 54,199
  • 15
  • 94
  • 116
  • Yep, it's something that can catch you off guard. Fortunately (or unfortunately ) there's a lot of third party nullable datetypeicker controls out there - http://www.google.com/search?q=nullable+datetimepicker – Dan F Jun 06 '10 at 09:54
  • For others that might come to this question by searching for a similar problem in WPF's datepicker: use a nullable DateTime (`DateTime?`) as Binding source to solve this problem – Breeze Nov 30 '15 at 08:57
18

You can check if your binding source delivers a "null date" or a date value that you don't want to display.

If so, select custom format:

yourDTP.Format = DateTimePickerFormat.Custom
yourDTP.CustomFormat = " "

Add a "CloseUp" or "ValueChanged" event handler to reset the format on user action:

yourDTP.Format = DateTimePickerFormat.Short
AvS
  • 180
  • 1
  • 4
  • 2
    This is the simplest and most elegant solution. Should be the accepted answer. – Vishnoo Rath Jul 05 '16 at 14:17
  • As @VishnooRath pointed out, this is the only solution that conveys the real meaning that we want to show to the user: there is no value at all; the user don't cares if it is null or datetime.min struct value ou whatever... – Marcelo Scofano Diniz Apr 29 '22 at 01:53
  • what if user wants to clear the value(to set it to null again)? – kgzdev Mar 08 '23 at 21:25
2

I like the ShowCheckBox option. I would take it one step further and encapsulate it with two extension methods to avoid duplication and have cleaner looking code:

public static DateTime? NullableValue(this DateTimePicker dtp)
{
    return dtp.Checked ? dtp.Value : (DateTime?)null;
}

public static void NullableValue(this DateTimePicker dtp, DateTime? value)
{
    dtp.Checked = value.HasValue;
    if (value.HasValue) dtp.Value = value.Value;
}

Then, the get and set code looks like:

dtpSafetyApprover.NullableValue(model.SafetyApproverDate); // set
model.SafetyApproverDate = dtpSafetyApprover.NullableValue(); // get
James R.
  • 822
  • 8
  • 17
2

The easiest way is to add a text box and set the visible property to false. On the valuechanged event of the date picker populate the text box with the same date time value of the picker control. Check the value of the text box if null string set the value to null.

2

this is how i solved it. I couldn't have NULLS so I defined 1/1/1980 12am as MYNULLDATE. I used databinding on the text and value of the datetimepicker. I did not use the checkbox in the datetimepicker. I did not alternat formats from short to custom. It appeared to fire valuechanged events so i just used custom and changed the customformat. I used a flowpanel and a NONBOUND checkbox to sit in front of the datetimepicker.

Sample of the code

   private void dateTimePicker_ValueChanged(object sender, EventArgs e)
    {
        if (sender != null && sender.GetType() == typeof(DateTimePicker))
        {
            if (((DateTimePicker)(sender)).Value == MYNULLDATE)
            {
                ((DateTimePicker)(sender)).CustomFormat = " ";
                checkBoxDate.Checked = false;
            }
            else
            {
                ((DateTimePicker)(sender)).CustomFormat = "M/d/yyyy";
                checkBoxDate.Checked = true;
            }
        }

    }

In the Non Bound CheckBox

  private void checkBoxDate_Click(object sender, EventArgs e)
    {
        if (bindingSource != null && bindingSource.Current != null &&
             bindingSource.Current.GetType() == typeof(MyRecord))
        {
            MyRecord a = (MyRecord)bindingSource.Current;
            if (checkBoxDate.Checked == false)
            {
                a.Date = MYNULLDATE;
                dateTimePicker.Enabled = false;
            }
            else
            {
                if (a.Date == null || a.Date == MYNULLDATE)
                {
                    dateTimePicker.Enabled = true;
                    a.Date = DateTime.Now;
                }
            }
            bindingSource.ResetBindings(false);
        }
    }
yolomann
  • 21
  • 1
0

Using Vs 2015 and having no luck binding a DateTimePicker control. The easiest thing seems to be simply not binding it- handle passing the value of your object to the control and from the control to your object manually. A few lines of code will save you lots of headaches...

private void BindData()
{
    // can't bind the datetimepicker, so handle it manually...
    if (o.myDate == null)
    {
        dtDatePicker.Checked = false;
    }
    else
    {
        dtDatePicker.Checked = true;
        dtDatePicker.Value = o.myDate.Value;
    }
}

private void Save()
{
    if (dtDatePicker.Checked)
    {
        o.myDate = dtDatePicker.Value;
    }
    else
    {
        o.myDate = null;
    }
}