(使用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'的无效转换
我看过演员讨论和参考书,但没有看到任何明显的问题。
有什么想法吗?
答案 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
事件由以下方式处理:
e.Value
(最初类型为string
,而DesiredType
为GridValueGroup
)成为所需类型。这样我就可以避免创建一个新对象,因为该单元已经有了该对象。
它还将输入的值保留在数据源中。尚不确定是否会阻止其他事件(有时在解析值后必须处理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;
}