DataGridView中的InvalidCastException

时间:2010-03-24 20:46:32

标签: c# datagridview struct .net

(使用VS 2010 Beta 2 - .Net 4.0 B2 Rel)

我有一个类MyTable,派生自BindingList,其中S是一个结构。 S由几个其他结构组成,例如:

public class MyTable<S>:BindingList<S> where S: struct
{
    ...
}

public struct MyStruct
{
    public MyReal r1;
    public MyReal r2;

    public MyReal R1 {get{...} set{...}}
    public MyReal R2 {get{...} set{...}}

    ...
}

public struct MyReal
{
    private Double d;

    private void InitFromString(string) {this.d = ...;}

    public MyReal(Double d) { this.d = d;}
    public MyReal(string val) { this.d = default(Double);  InitFromString(val);}

    public override string ToString() { return this.real.ToString();}
    public static explicit operator MyReal(string s) { return new MyReal(s);}
    public static implicit operator String(MyReal r) { return r.ToString();}
    ...
}

好的,我使用MyTable作为DataGridView的绑定源。我可以在MyStruct中的各个字段上使用InitFromString轻松加载数据网格。

当我尝试编辑DataGridView的单元格中的值时出现问题。转到第一行,第一列,我更改现有数字的值。它提供了一个例外的暴风雪,其第一行说:

System.FormatException:从'System.String'到'MyReal'的无效转换

我看过演员讨论和参考书,但没有看到任何明显的问题。

有什么想法吗?

4 个答案:

答案 0 :(得分:3)

我尝试了处理CellParsing的方法,但它确实有效。虽然我做的有点不同,处理任何类型:

    private void dataGridView1_CellParsing(object sender, DataGridViewCellParsingEventArgs e)
    {
        e.Value = Activator.CreateInstance(e.DesiredType, new object[] { e.Value });
        e.ParsingApplied = true;
    }

答案 1 :(得分:2)

DataGridView使用TypeConverter

您必须为您的结构定义一个TypeConverter对象,并用TypeConverterAttribute装饰它,以便DataGridView在遇到用您的结构键入的属性时立即使用它。

我在这里给出的这样一个TypeConverter的示例有点基本,但是我使用的Degree结构与您的类似,它将为您提供一个很好的主意。

[TypeConverter(typeof(DegreeConverter))]
public struct Degree {
    double Value;
    public Degree(double v) { Value = v; }
    public static implicit operator double(Degree v) => v.Value;
    public static implicit operator Degree(double v) => new Degree(v);
    public override string ToString() => Value.ToString();
}

class DegreeConverter : TypeConverter {
    public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType) {
        return sourceType == typeof(string) ? true : base.CanConvertFrom(context, sourceType);
    }

    public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType) {
        return destinationType == typeof(string) ? true : base.CanConvertTo(context, destinationType);
    }

    public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value) {
        return new Degree(Convert.ToDouble(value));
    }

    public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType) {
        return value.ToString();
    }
}

答案 2 :(得分:0)

我(几乎)通过处理CellParsing事件来解决这个问题,例如

private void dataGridView1_CellParsing(object sender, DataGridViewCellParsingEventArgs e)
{
    ... // (checking goes here)
    e.Value = new MyReal(e.Value.ToString());
    e.ParsingApplied = true;
}

e.Value正确设置但DataGridView仍显示旧值。新值如何放在BindingList中?

我是否需要一个显式方法调用来强制将新值强制进入BindingList,如果是,那么在哪里?

答案 3 :(得分:0)

我的gridcells填充了GridValueGroup类型的对象,并且ObjValue覆盖显示了ToString属性。修改网格单元格中的字符串时,CellParsing事件由以下方式处理:

  1. 填写单元格值
  2. 修改e.Value(最初类型为string,而DesiredTypeGridValueGroup)成为所需类型。
  3. 这样我就可以避免创建一个新对象,因为该单元已经有了该对象。

    它还将输入的值保留在数据源中。尚不确定是否会阻止其他事件(有时在解析值后必须处理CellValueChanged)。

         private void grid_CellParsing(object sender, DataGridViewCellParsingEventArgs e) {
            string val = e.Value.ToString();
    
            DataGridViewCell cell = this.dgvGroup1[e.ColumnIndex, e.RowIndex];
    
            if (e.DesiredType == typeof(GridValueGroup))
            {
                ((GridValueGroup)cell.Value).ObjValue = val;
                e.Value = ((GridValueGroup)cell.Value);
            }
            e.ParsingApplied = true;
    
        }