【问题标题】:InvalidCastException in DataGridViewDataGridView 中的 InvalidCastException
【发布时间】:2010-03-24 20:46:32
【问题描述】:

(使用 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”的无效转换

我查看了选角讨论和参考书,但没有发现任何明显的问题。

有什么想法吗?

【问题讨论】:

  • 这是 System.FormatException,而不是 InvalidCastException?检查堆栈跟踪,是什么引发了异常?
  • 可能是因为您的运算符从字符串转换为实数是显式的而不是隐式的?
  • 这两个例外。默认错误对话框报告'System.FormatException:Invalid cast from 'System.String' to 'MyReal' --> System.InvalidCastException: Invalid cast from 'System.String' to 'MyReal'
  • 我认为我需要明确处理解析和格式化事件,而不是使用默认处理程序。
  • @MaxYaffe 刚刚回顾了我发布的一些旧答案,我想知道我们对此是否有任何帮助?

标签: c# datagridview struct .net


【解决方案1】:

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

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

【讨论】:

    【解决方案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();
        }
    }
    

    【讨论】:

      【解决方案3】:

      我(几乎)通过处理 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,如果需要,在哪里?

      【讨论】:

        【解决方案4】:

        我的网格单元中填充了 GridValueGroup 类型的对象,并且它们具有由 ToString 覆盖显示的 ObjValue 属性。修改网格单元格中的字符串时,CellParsing事件由:

        1. 填充单元格值和
        2. 修改e.Value(最初是string类型,而DesiredTypeGridValueGroup)成为所需的类型。

        这样我可以避免创建一个新对象,因为单元格已经有了那个对象。

        它还将输入的值保留在数据源中。尚不确定它是否会阻止其他事件(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;
        
            }
        

        【讨论】:

          猜你喜欢
          • 2012-02-06
          • 1970-01-01
          • 2016-12-17
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多