WinForms – DataBinding DateTimePicker to a Nullable Type

I’ve used basic data binding in WinForms 2.0 a couple of times, but encountered something new to me this past week.  We have a form that has a DateTimePicker control (including ShowCheckBox=true) and want to bind it to a Nullable object property.  The requirement here is that the data value is optional for the user to enter (say, tracking a customer’s Birthday) – so if there is no date entered, we want our data value to have null (and therefore, the DB has NULL). 

We can’t setup standard databinding on the DataBindings collection … 

    dtBirthdayNullable.DataBindings.Clear(); 

    dtBirthdayNullable.DataBindings.Add( “Value”, person, “BirtdayNullable” ); 

…but this throws an exception – since the DateTimePicker.Value property can’t be null. 

From here I know that we need to control the data going into, and coming out of, the DateTimePicker control during the data binding process.  This is where the Format and Parse events come in handy.  The Format event lets you control how you handle data coming out of the object and going into the control property.  The Parse event allows you to control how you deal with data coming out of the control before it gets set on your object property. 

We setup the DataBindings using a Binding object, so we can hookup the event handlers: 

    Binding b = new Binding( “Value”, person, “BdayNullable”, true ); 

    dtBirthdayNullable.DataBindings.Add( b ); 

    b.Format += new ConvertEventHandler( dtBirthdayNullable_Format ); 

    b.Parse += new ConvertEventHandler( dtBirthdayNullable_Parse ); 

Of special importance is the 4th parameter on the Binding constructor.  This is to set formattingEnabled, so that we get the format event on the way in to the control. 

Finally, the event handlers, and the trick in the Format method: 

// OBJECT PROPERTY –> CONTROL VALUE 

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 == null

            { 

                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. 

            } 

  

        } 

    } 

The key above is that we have to set the e.Value property to something (since the DateTimePicker control is not happy with a null value), but if we set it to something different than what it already is, the control interprets this just like the user changed the value, and therefore sets the checkmark (opposite of what we want/need). 

So the trick is that we’ll set e.Value to the what the DateTimePicker.Value already has.   

Finish up with the Parse method, which will handle the data coming out of the control and into our object Property.  Pretty straight forward: 

// CONTROL VALUE –> OBJECT PROPERTY 

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 = new Nullable(); 

            } 

            else 

            { 

                DateTime val = Convert.ToDateTime( e.Value ); 

                e.Value = new Nullable( val ); 

            } 

        } 

    } 

11 thoughts on “WinForms – DataBinding DateTimePicker to a Nullable Type

  1. In VB 2008, I find the following works for me on nullable date/time fields:

    Private Sub BindThis()

    Me.dtBirthdayNullable.DataBindings.Clear()
    Me.dtBirthdayNullable.DataBindings.Add(“Value”, person, “BdayNullable”, True, DataSourceUpdateMode.OnPropertyChanged, Now()) ‘Now() is the default if empty – change to whatever

    If IsDBNull(person.BdayNullable) _
    Or person.BdayNullable Is Nothing Then
    Me.dtBirthdayNullable.CustomFormat = ” ” ‘This blanks out the contents of the DateTimePicker so it “shows” as having chosen nothing yet
    Me.dtBirthdayNullable.Checked = False
    Else
    Me.dtBirthdayNullable.CustomFormat = “ddd dd/MM/yyyy” ‘or whatever format you wish
    End If

    End Sub

    ‘Then just add an event for when the user selects the dateTimePicker so that they see a date on control enter:
    Private Sub dtBirthdayNullable_Enter(ByVal sender As Object, ByVal e As System.EventArgs) Handles dtBirthdayNullable.Enter

    If Me.dtBirthdayNullable.CustomFormat = ” ” Then Me.dtBirthdayNullable.CustomFormat = “ddd dd/MM/yyyy”

    End Sub

  2. FYI
    error CS0118: ‘System.Nullable’ is a ‘type’ but is used like a ‘variable’
    error CS0712: Cannot create an instance of the static class ‘System.Nullable

  3. But give an error at line : e.Value = new Nullable( val );
    and
    e.Value = new Nullable();
    Error : “Cannot create an instance of the static class ‘System.Nullable”
    Any solution/

  4. Odd, I posted the correct code but it got altered. Here is a second attempt with spaces added to preserve formatting:

    DateTime val = Convert.ToDateTime(e.Value);
    e.Value = new Nullable (val);

  5. Okay, I see the issue. The forum is reformatting the actual code. To get around that i will substitute characters.
    Lower case v with underscores (_v_) will be used as the less-than/left pointing character.
    Upper case V with underscores (_V_) will be used as the greater-than/right pointing character.

    DateTime val = Convert.ToDateTime(e.Value);
    e.Value = new Nullable_v_DateTime_V_(val);

    Hope this posts.

Leave a Reply

Your email address will not be published. Required fields are marked *