A few years ago I began searching for a DateTimePicker control that supports Nullable dates, including the VBForums website (see below link).
https://www.vbforums.com/showthread....light=nullable
There are commercial products that include a nullable DateTimePicker control, but I was looking for a less expensive solution.
I have since developed a custom nullable DateTimePicker control, with help from ChatGPT, that includes the following features:
• Nullable DateTime support
• Bindable NullableValue property
• Designer-friendly (shows in toolbox, works in DataBindings window)
• Delete/Backspace clears value
• Optional NullText
• Works with BindingSource, DataTable, or custom objects
• Fires NullableValueChanged and PropertyChanged
The NullableDateTimePicker control exposes several properties, including a bindable NullableValue property, shown below.
How it works (short version -- see code comments for additional details):Code:<Browsable(True), Category("Data"), Description("Nullable date value (Nothing means no date).")> Public Property NullableValue As DateTime? Get Return _nullableValue End Get Set(value As DateTime?) If Nullable.Equals(_nullableValue, value) Then Exit Property _nullableValue = value If value.HasValue Then Me.Format = DateTimePickerFormat.Short MyBase.Value = ClampToValidRange(value.Value) Else Me.Format = DateTimePickerFormat.Custom Me.CustomFormat = _nullText End If UpdateDisplayFromNullable() OnNullableValueChanged(EventArgs.Empty) OnPropertyChanged(NameOf(NullableValue)) End Set End Property
• When NullableValue is Nothing, the control switches to Format = Custom and sets CustomFormat to a blank string (or your NullText) so it appears empty.
• When NullableValue has a Date, the control restores a normal date format and sets the Value.
• Pressing Delete (or Backspace) clears the value.
• NullableValueChanged lets you react when it changes.
Here is a screenshot of the control.
The above form (frmMain) shows 2 instances of the NullableDateTimePicker control. The ndtpDOB shows the birth date which is required (cannot be nothing) and the ndtpDOD shows the death date (which can be nothing). The TextBox and NullableDateTime controls are data-bound to a datatable and the form's StatusStrip shows the auto-increment field of the datatable.
The frmMain form's ndtp_Validating and ndtp_Validated methods handle updates to the bindingsource (bsMain) for these 2 NullabelDataTimePicker controls as show below.
Code:Private Sub ndtp_Validating(sender As Object, e As CancelEventArgs) Handles ndtpDOB.Validating, ndtpDOD.Validating 'e.Cancel = True '...do not proceed to the control's Validated method 'e.Cancel = False '...proceed to the control's Validated method (this is the default) Dim ndtp = DirectCast(sender, NullableDateTimePicker) If flgDebug Then Debug.WriteLine("{0}, {1}", Date.Now, ndtp.Name & "_Validating (" & If(ndtp.NullableValue.HasValue, ndtp.NullableValue.Value.ToString, "Nothing") & ")") Select Case ndtp.Name Case "ndtpDOB" If ndtp.NullableValue Is Nothing Then '...at this point the NullableValue = Nothing '...when NullableValue = Nothing, the control switches to Format = Custom and CustomFormat = "' '" (i.e., a blank string) ' which causes the DateTimePicker to render no visible text and to the user, the control looks empty or invisible ' because there’s no border, no placeholder, no content — just blank space. '...re-set the NullableValue *before* displaying the MessageBox so that the control is visible when the MessageBox is displayed ndtp.NullableValue = CDate(ndtp.Tag) '...restore previous NullableValue value MessageBox.Show("The date of birth cannot be Nothing.", "Validating", MessageBoxButtons.OK, MessageBoxIcon.Exclamation) e.Cancel = False '...proceed to the control's Validated method Else e.Cancel = False '...proceed to the control's Validated method End If Case "ndtpDOD" e.Cancel = False '...proceed to the control's Validated method End Select End SubThe attached compressed zip file contains the class for the NullableDateTimePicker control and the frmMain form that demonstrates the use of this custom control.Code:Private Sub ndtp_Validated(sender As Object, e As EventArgs) Handles ndtpDOB.Validated, ndtpDOD.Validated Dim ndtp = DirectCast(sender, NullableDateTimePicker) Dim currentRow = DirectCast(bsMain.Current, DataRowView) If flgDebug Then Debug.WriteLine("{0}, {1}", Date.Now, ndtp.Name & "_Validated (" & If(ndtp.NullableValue.HasValue, ndtp.NullableValue.Value.ToString, "Nothing") & ")") Select Case ndtp.Name Case "ndtpDOB" If CDate(currentRow("BirthDate")) <> ndtp.NullableValue.Value Then '...commit edits for the current item in the bindinglist ("BirthDate") to the underlying datatable (bs.DataSource) currentRow("BirthDate") = ndtp.NullableValue.Value End If Case "ndtpDOD" 'currentRow("DeathDate") = If(ndtp.NullableValue.HasValue, ndtp.NullableValue.Value, Nothing) ' This line causes the control to show #1/1/1753# because: ' • You're assigning Nothing (VB.NET's Nothing = default value for value types) ' • The column is typed as Date (i.e., DateTime) ' • So Nothing becomes Date.MinValue ? #1/1/0001# ' • But since DateTimePicker.MinDate is #1/1/1753#, it clamps the value up to #1/1/1753# ' • Thus, your control ends up showing #1/1/1753# ' If the ndtp.NullableValue is Nothing, then this line causes an Option Strict issue ("Cannot infer a common type, and Option Strict On does not allow 'Object' to be assumed"). ' currentRow("DeathDate") = If(ndtp.NullableValue.HasValue, ndtp.NullableValue.Value, DBNull.Value) ' The "safe" technique is to use an Object variable explicitly. Dim val As Object = If(ndtp.NullableValue.HasValue, CType(ndtp.NullableValue.Value, Object), DBNull.Value) ' Nullable.Equals(objA, objB) is specific for for nullable value types and handles: ' • Both being Nothing: returns True ' • Both being equal non-null values: returns True ' • Otherwise: returns False If Not Nullable.Equals(currentRow("DeathDate"), val) Then '...commit edits for the current item in the bindinglist ("DeathDate") to the underlying datatable (bs.DataSource) currentRow("DeathDate") = val End If End Select ndtp.Tag = ndtp.NullableValue End Sub
Do the following to build a demo project using this control:
1. Extract the NullableDateTimePicker.vb class file and frmMain.vb form file from the attached zip file.
1. Create a new Windows Forms App (.NET framework).
2. Add the NullableDateTimePicker class to the project.
3. Add the frmMain form to the project.
4. Build (compile) and run the project.
I welcome any feedback, including suggestions to improve/enhance the NullableDateTimePicker control.




Reply With Quote
