[2.0] Binding to my NullableDateTimePicker control
With the addition of Nullable Types to C# 2.0, I wrote my own NullableDateTimePicker control in very few lines of code, as opposed to the nullable DateTimePicker controls I've found that were written for C# 1.1.
csharp Code:
public partial class NullableDateTimePicker : DateTimePicker
{
private DateTime? dtNullable;
public NullableDateTimePicker()
{
base.Format = DateTimePickerFormat.Custom;
base.CustomFormat = " ";
}
public new DateTime? Value
{
get
{
if (dtNullable.HasValue)
return base.Value;
return null;
}
set
{
if (value == null)
dtNullable = null;
else
dtNullable = base.Value = value.Value;
OnValueChanged(EventArgs.Empty);
}
}
protected override void OnValueChanged(EventArgs eventargs)
{
if (this.dtNullable.HasValue)
{
base.Format = DateTimePickerFormat.Short;
}
else
{
base.Format = DateTimePickerFormat.Custom;
base.CustomFormat = " ";
}
base.OnValueChanged(eventargs);
}
protected override void OnCloseUp(EventArgs eventargs)
{
if (Control.MouseButtons == MouseButtons.None)
{
this.Value = base.Value;
}
base.OnCloseUp(eventargs);
}
}
Which is alright except if I bind the Value property and the binding source returns a DBNull.Value then I get the following error:
error Code:
Invalid cast from 'System.DateTime' to 'System.Nullable`
How can I represent a DateTime so that it may contain a valid DateTime, and instead of null, DBNull.Value?
Re: [2.0] Binding to my NullableDateTimePicker control
Where does this exception get thrown exactly?
Re: [2.0] Binding to my NullableDateTimePicker control
Quote:
Originally Posted by jmcilhinney
Where does this exception get thrown exactly?
On the last line:
csharp Code:
Binding b = new Binding("Value", this.bindingSource1,
this.notesDataSet.StatusNotes.DateEnteredColumn.ColumnName);
this.nullableDateTimePicker1.DataBindings.Add(b);
Re: [2.0] Binding to my NullableDateTimePicker control
Change the Set code for the Value property to this:
Code:
set
{
if (value == null || value == DBNull.Value)
dtNullable = null;
else
dtNullable = base.Value = value.Value;
OnValueChanged(EventArgs.Empty);
}
Re: [2.0] Binding to my NullableDateTimePicker control
Quote:
Originally Posted by MetalKid
Change the Set code for the Value property to this:
Code:
set
{
if (value == null || value == DBNull.Value)
dtNullable = null;
else
dtNullable = base.Value = value.Value;
OnValueChanged(EventArgs.Empty);
}
Nope. That won't even begin to compile.
DateTime? cannot be converted to DBNull.Value.
Re: [2.0] Binding to my NullableDateTimePicker control
Alright, what about this?
Code:
set
{
if (value == null || !value.HasValue)
dtNullable = null;
else
dtNullable = base.Value = value.Value;
OnValueChanged(EventArgs.Empty);
}
Re: [2.0] Binding to my NullableDateTimePicker control
Quote:
Originally Posted by MetalKid
Alright, what about this?
Code:
set
{
if (value == null || !value.HasValue)
dtNullable = null;
else
dtNullable = base.Value = value.Value;
OnValueChanged(EventArgs.Empty);
}
No!
The Value property has to accept DBNull.Value to be able to bind to database nulls.
Re: [2.0] Binding to my NullableDateTimePicker control
There really isn't anything you can do to the control's code to fix this except make it take an object instead of that nullable type and then do some type checking in the set and get... I think you'd have to go thru datatable that comes back and change any values that are DBNull.Value to null...
Re: [2.0] Binding to my NullableDateTimePicker control
Quote:
Originally Posted by MetalKid
There really isn't anything you can do to the control's code to fix this except make it take an object instead of that nullable type and then do some type checking in the set and get... I think you'd have to go thru datatable that comes back and change any values that are DBNull.Value to null...
I've already done that. That's what most of the samples for C# 1.1 do. I hoped there was a better way with Nullable types in C# 2.0.
Re: [2.0] Binding to my NullableDateTimePicker control
So I decided it would be easiest to let Value be an object and then handle casting from the UI. Actually, I don't even have to cast if I bind the "Value" of the control to a DataSet member. The control works fine, binds to DBNull OK and if a new date is chosen from the DateTimePicker everything is fine.
Problem is, if I set the Value of the control in code, the date displays properly, but isn't updated in the DataSet. So if I call Update from the DataAdapter, the column isn't updated.
Is there anything I'm missing to get it to update the DataSet if the Value is set in code?
csharp Code:
public partial class NullableDateTimePicker : DateTimePicker
{
private object dtNullable;
private bool isFormatting;
public NullableDateTimePicker()
{
base.Format = DateTimePickerFormat.Custom;
base.CustomFormat = " ";
}
#region Properties
public new object Value
{
get
{
if(this.dtNullable != null)
return base.Value;
return DBNull.Value;
}
set
{
if (!this.isFormatting)
{
if (value == DBNull.Value)
{
dtNullable = null;
}
else
{
this.dtNullable = base.Value = Convert.ToDateTime(value);
}
}
this.OnValueChanged(EventArgs.Empty);
}
}
#endregion
#region Methods
#region Overrides
protected override void OnValueChanged(EventArgs eventargs)
{
if (!this.isFormatting)
{
this.isFormatting = true;
if (this.dtNullable != null)
{
if (base.Format != DateTimePickerFormat.Short)
base.Format = DateTimePickerFormat.Short;
}
else
{
if (base.Format != DateTimePickerFormat.Custom)
base.Format = DateTimePickerFormat.Custom;
base.CustomFormat = " ";
}
}
this.isFormatting = false;
base.OnValueChanged(eventargs);
}
protected override void OnCloseUp(EventArgs eventargs)
{
if (Control.MouseButtons == MouseButtons.None)
{
this.Value = this.dtNullable = base.Value;
}
base.OnCloseUp(eventargs);
}
protected override void OnKeyUp(KeyEventArgs e)
{
if (e.KeyCode == Keys.Delete)
{
this.Value = DBNull.Value;
}
base.OnKeyUp(e);
}
#endregion
#endregion
}
Re: [2.0] Binding to my NullableDateTimePicker control
More background info...
I just discovered that if I set the Value of the NullableDateTimePicker through code, but click into the control to give it the focus, then remove the focus, the control updates properly. I hooked up a Parse event to the DataBinding to Value and the only time the Parse event fires is if the control gains and loses focus.
I guess my only option is, after the Value is changed through code, to trick the control into thinking it gained and lost focus, which I can't seem to do. Even if I set the Focus through code and/or fire the OnMouseClickEvent, it still won't update. Only if I click in and out of the control.