Ivan-Mark Debono
Ivan-Mark Debono

Reputation: 16280

DataGridView trying to cast from string to object

I have a custom control whose Value property is an object. The control also has a Text property which, depending on the object, displays an object's string property.

This custom control is hosted within a DataGridView and I implemented the required interface IDataGridViewEditingControl to get it working. I also have 2 classes inheriting from DataGridViewColumn and DataGridViewTextBoxCell.

The CustomerTypeDto class:

public class CustomerTypeDto
{
    public int Id {get; set;}
    public int Description {get; set}
    //Other properties...
}

One remaining problem is that after I select a value from the control and the DataGridView tries to end the cell edit, I get the following exception:

System.FormatException: Invalid cast from 'System.String' to 'CustomerTypeDto'. ---> System.InvalidCastException: Invalid cast from 'System.String' to 'CustomerTypeDto'. at System.Convert.DefaultToType(IConvertible value, Type targetType, IFormatProvider provider) at System.String.System.IConvertible.ToType(Type type, IFormatProvider provider) at System.Convert.ChangeType(Object value, Type conversionType, IFormatProvider provider) at System.Windows.Forms.Formatter.ChangeType(Object value, Type type, IFormatProvider formatInfo) --- End of inner exception stack trace --- at System.Windows.Forms.Formatter.ChangeType(Object value, Type type, IFormatProvider formatInfo) at System.Windows.Forms.Formatter.ParseObjectInternal(Object value, Type targetType, Type sourceType, TypeConverter targetConverter, TypeConverter sourceConverter, IFormatProvider formatInfo, Object formattedNullValue) at System.Windows.Forms.Formatter.ParseObject(Object value, Type targetType, Type sourceType, TypeConverter targetConverter, TypeConverter sourceConverter, IFormatProvider formatInfo, Object formattedNullValue, Object dataSourceNullValue) at System.Windows.Forms.DataGridViewCell.ParseFormattedValueInternal(Type valueType, Object formattedValue, DataGridViewCellStyle cellStyle, TypeConverter formattedValueTypeConverter, TypeConverter valueTypeConverter) at System.Windows.Forms.DataGridViewCell.ParseFormattedValue(Object formattedValue, DataGridViewCellStyle cellStyle, TypeConverter formattedValueTypeConverter, TypeConverter valueTypeConverter) at System.Windows.Forms.DataGridView.PushFormattedValue(DataGridViewCell& dataGridViewCurrentCell, Object formattedValue, Exception& exception)

Which method or property do I need to override so that the DataGridView can cast from my object to string and vice-versa.

And should I inherit from DataGridViewTextBoxCell or from DataGridViewCell directly?

EDIT

This is my cell class:

public class CustomerTypeCell : DataGridViewTextBoxCell
{
    public CustomerTypeCell()
        : base()
    { }

    public override void InitializeEditingControl(int rowIndex, object initialFormattedValue, DataGridViewCellStyle dataGridViewCellStyle)
    {
        base.InitializeEditingControl(rowIndex, initialFormattedValue, dataGridViewCellStyle);

        CustomControl ctl = DataGridView.EditingControl as CustomControl;

        if (this.Value == null)
            ctl.Value = (CustomerTypeDto)this.DefaultNewRowValue;
        else
            ctl.Value = (CustomerTypeDto)this.Value;
    }

    public override Type EditType
    {
        get { return typeof(CustomControl); }
    }

    public override Type ValueType
    {
        get { return typeof(CustomerTypeDto); }
    }

    public override object DefaultNewRowValue
    {
        get { return null; }
    }

    public override object ParseFormattedValue(object formattedValue, DataGridViewCellStyle cellStyle, TypeConverter formattedValueTypeConverter, TypeConverter valueTypeConverter)
    {
        return base.ParseFormattedValue(formattedValue, cellStyle, formattedValueTypeConverter, valueTypeConverter);
    }
}

The property FormattedValueType in DataGridViewTextBoxCell always returns string.

And in the method ParseFormattedValue above, it's trying to cast from string to my object. The description of this method :

Converts a value formatted for display to an actual cell value.

But this doesn't make sense because the Value is of type CustomerTypeDto, so how is this parsing going to work?

Basically what I'm trying to do is let the user select a CustomerType object from my custom control. This object should be the cell's value, and the value's text (in this case the Description property) is displayed as a string in the cell.

I do not understand why the DataGridView wants to parse the string in an object if I already have the object in the cell's value property.

Upvotes: 3

Views: 2318

Answers (3)

Tobias Knauss
Tobias Knauss

Reputation: 3509

This question is already answered with 2 working solutions in Custom Control in DataGridView Cell Throws FormatException When Editing

The first answer https://stackoverflow.com/a/36656360 is only working with my comment, thus the full solution is

public object GetEditingControlFormattedValue (DataGridViewDataErrorContexts context)
{
  if ((context & DataGridViewDataErrorContexts.Parsing) != 0)
  {
    // Here you should not return string, but your value
    return Value;
  }
  return EditingControlFormattedValue;
}

public override object ParseFormattedValue (object formattedValue,
                                            DataGridViewCellStyle cellStyle,
                                            TypeConverter formattedValueTypeConverter,
                                            TypeConverter valueTypeConverter)
{
  if (formattedValue is CustomerTypeDto)
  {
    return formattedValue;
  }
  return base.ParseFormattedValue (formattedValue, cellStyle, formattedValueTypeConverter, valueTypeConverter);
}

The second answer https://stackoverflow.com/a/36668621 works as expected.

Upvotes: 0

Sergey Rog
Sergey Rog

Reputation: 21

if you want to implement your value ahead of time, use method e.ParsingApplied = true;after you implement to e.Value = (ObjOfYourType) i have used it in event CellParsing that is caused before dropping an exception.

Upvotes: 2

pwnyexpress
pwnyexpress

Reputation: 1016

Your CustomerTypeDto class needs an explicit cast operator for the string type.

class CustomerTypeDto
{
    // string -> CustomerTypeDto
    public static explicit operator CustomerTypeDto(string s)
    {
        CustomerTypeDto ctd = new CustomerTypeDto();
        // ... do something with the string.
        return ctd;
    }
    // CustomerTypeDto -> string
    public static explicit operator String(CustomerTypeDto ctd)
    {
        return ctd.toString();
        // or some other way to return it's string value.
    }
    // other stuff...
}

So you can do things like this:

return (CustomerTypeDto)someString;

Upvotes: 1

Related Questions