C# – Binding to a Nullable control property

cdata-bindingdatetimenullablewinforms

We have a custom control that has a "Value" property of type System.Nullable (aka System.DateTime?). We have an object with a "Received" property of the same type. When we try to bind the control to the object, the following InvalidCastException is thrown:

Invalid cast from 'System.DateTime' to 'System.Nullable`1[[System.DateTime, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]]'.

Here is what we're doing:

Object property:

private System.DateTime? _dateTimeReceived;
public System.DateTime? DateTimeReceived
{
    get
    {
        return this._dateTimeReceived;
    }
    set
    {
        this._dateTimeReceived = value;
        this.OnChanged("DateTimeReceived", value); //Implements INotifyPropertyChanged and fires PropertyChanged event
    }
}

Control property:

private System.DateTime? _value;
[System.ComponentModel.Category("Behavior")]
[System.ComponentModel.Description("The current date value for this control")]
public new System.DateTime? Value
{
    get
    {
        return this._value;
    }

    set
    {
        this._value = value;
    }
}

In the application, here is where the exception is thrown:

this.dateReceived.DataBindings.Add("Value", this._object, "DateTimeReceived");

As you can see, the object's property (this._object.DateTimeReceived) is a System.DateTime? type and the control's property (this.dateReceived.Value) is a System.DateTime? type.

Why would this cause an InvalidCastException? And how can we correct this so that it binds correctly?

Update 2009-10-29 14:26 CDT:

Here is the stack trace:

at System.Convert.DefaultToType(IConvertible value, Type targetType,
IFormatProvider provider)
at
System.DateTime.System.IConvertible.ToType(Type type, IFormatProvider
provider)
at System.Convert.ChangeType(Object value, Type
conversionType, IFormatProvider provider)
at
System.Windows.Forms.Binding.FormatObject(Object value)
at
System.Windows.Forms.Binding.PushData(Boolean force)
at
System.Windows.Forms.Binding.UpdateIsBinding()
at
System.Windows.Forms.Binding.CheckBinding()
at
System.Windows.Forms.Binding.SetListManager(BindingManagerBase
bindingManagerBase)
at
System.Windows.Forms.ListManagerBindingsCollection.AddCore(Binding
dataBinding)
at
System.Windows.Forms.BindingsCollection.Add(Binding binding)
at
System.Windows.Forms.BindingContext.UpdateBinding(BindingContext
newBindingContext, Binding binding)
at
System.Windows.Forms.Binding.SetBindableComponent(IBindableComponent
value)
at
System.Windows.Forms.ControlBindingsCollection.AddCore(Binding
dataBinding)
at
System.Windows.Forms.BindingsCollection.Add(Binding binding)
at
System.Windows.Forms.ControlBindingsCollection.Add(String
propertyName, Object dataSource, String dataMember, Boolean
formattingEnabled, DataSourceUpdateMode updateMode, Object nullValue,
String formatString, IFormatProvider formatInfo)
at
System.Windows.Forms.ControlBindingsCollection.Add(String
propertyName, Object dataSource, String dataMember)

Best Answer

I was trying to do the same thing, and I managed to find some working sample code which bound to a nullable. It turns out that if you set the formattingEnabled to true, it works, but if it's false, you get the invalid cast exception.

So your code that looks like this:

this.dateReceived.DataBindings.Add("Value", this._object, "DateTimeReceived");

Should instead look like this:

this.dateReceived.DataBindings.Add("Value", this._object, "DateTimeReceived", true);

Apparently the old data binding code requires that the types match exactly, but Microsoft later added the ability to automatically convert types for you. From here: http://msdn.microsoft.com/en-us/library/aa480734.aspx

In earlier versions of the .NET Framework you had to manually perform the type conversions and formatting using the Format and Parse events of the Binding object. You can now do this by enabling formatting on the Binding object, either by setting the FormattingEnabled property directly or passing true to the Add method of the ControlBindingsCollection.