DataGridViewComboBoxColumn 绑定对象集合时存在BUG?
DataGridview 绑定的是对象集合,里面有一列是下拉列表,也用集合绑定,一切看上去很美好,可是当我改变选择下拉列表时,却发生BUG。字符串不能转成对象!不知是DataGridview里的对应的下拉列表列保存的是字符串,还是下拉列表保存的是字符串。
查google 得知,下拉列表是以模板的方式进行编辑,这有点以前web 下的datagrid 吗
(既然编辑的时候用另一种控件,为何显视时不直接使用label算了,就象Infragistics UltraGrid)。于是创建一下模板列继承DataGridViewComboBoxCell。果然有ParseFormattedValue这个方法。跟踪,原来formattedValue传进来时是一个字符串类型。看来问题很容易解决吗,于是转成对象:
public override object ParseFormattedValue(object formattedValue, DataGridViewCellStyle cellStyle, TypeConverter formattedValueTypeConverter, TypeConverter valueTypeConverter)
{
ComboBox comboBox = base.DataGridView.EditingControl as ComboBox;
formattedValue = (BizObject)comboBox.SelectedItem;
return base.ParseFormattedValue(formattedValue, cellStyle, formattedValueTypeConverter, valueTypeConverter);
}
{
ComboBox comboBox = base.DataGridView.EditingControl as ComboBox;
formattedValue = (BizObject)comboBox.SelectedItem;
return base.ParseFormattedValue(formattedValue, cellStyle, formattedValueTypeConverter, valueTypeConverter);
}
这下好了,出现了新的问题
类型转化错误!由于调用了内部类,这下子跟踪不了了,反编译System.Windows.Forms,得到下面方法:
public override object ParseFormattedValue(object formattedValue, DataGridViewCellStyle cellStyle, TypeConverter formattedValueTypeConverter, TypeConverter valueTypeConverter)
{
if (valueTypeConverter == null)
{
if (this.ValueMemberProperty != null)
{
valueTypeConverter = this.ValueMemberProperty.Converter;
}
else if (this.DisplayMemberProperty != null)
{
valueTypeConverter = this.DisplayMemberProperty.Converter;
}
}
if (((this.DataManager != null) && ((this.DisplayMemberProperty != null) || (this.ValueMemberProperty != null))) || (!string.IsNullOrEmpty(this.DisplayMember) || !string.IsNullOrEmpty(this.ValueMember)))
{
object obj1 = base.ParseFormattedValueInternal(this.DisplayType, formattedValue, cellStyle, formattedValueTypeConverter, this.DisplayTypeConverter);
object obj2 = obj1;
if (!this.LookupValue(obj2, out obj1))
{
if (obj2 != DBNull.Value)
{
throw new FormatException(string.Format(CultureInfo.CurrentCulture, SR.GetString("Formatter_CantConvert"), new object[] { obj1, this.DisplayType }));
}
return DBNull.Value;
}
return obj1;
}
return base.ParseFormattedValueInternal(this.ValueType, formattedValue, cellStyle, formattedValueTypeConverter, valueTypeConverter);
}
internal object ParseFormattedValueInternal(Type valueType, object formattedValue, DataGridViewCellStyle cellStyle, TypeConverter formattedValueTypeConverter, TypeConverter valueTypeConverter)
{
if (cellStyle == null)
{
throw new ArgumentNullException("cellStyle");
}
if (this.FormattedValueType == null)
{
throw new FormatException(SR.GetString("DataGridViewCell_FormattedValueTypeNull"));
}
if (valueType == null)
{
throw new FormatException(SR.GetString("DataGridViewCell_ValueTypeNull"));
}
if ((formattedValue == null) || !this.FormattedValueType.IsAssignableFrom(formattedValue.GetType()))
{
throw new ArgumentException(SR.GetString("DataGridViewCell_FormattedValueHasWrongType"), "formattedValue");
}
return Formatter.ParseObject(formattedValue, valueType, this.FormattedValueType, (valueTypeConverter == null) ? this.ValueTypeConverter : valueTypeConverter, (formattedValueTypeConverter == null) ? this.FormattedValueTypeConverter : formattedValueTypeConverter, cellStyle.FormatProvider, cellStyle.NullValue, cellStyle.IsDataSourceNullValueDefault ? Formatter.GetDefaultDataSourceNullValue(valueType) : cellStyle.DataSourceNullValue);
}
{
if (valueTypeConverter == null)
{
if (this.ValueMemberProperty != null)
{
valueTypeConverter = this.ValueMemberProperty.Converter;
}
else if (this.DisplayMemberProperty != null)
{
valueTypeConverter = this.DisplayMemberProperty.Converter;
}
}
if (((this.DataManager != null) && ((this.DisplayMemberProperty != null) || (this.ValueMemberProperty != null))) || (!string.IsNullOrEmpty(this.DisplayMember) || !string.IsNullOrEmpty(this.ValueMember)))
{
object obj1 = base.ParseFormattedValueInternal(this.DisplayType, formattedValue, cellStyle, formattedValueTypeConverter, this.DisplayTypeConverter);
object obj2 = obj1;
if (!this.LookupValue(obj2, out obj1))
{
if (obj2 != DBNull.Value)
{
throw new FormatException(string.Format(CultureInfo.CurrentCulture, SR.GetString("Formatter_CantConvert"), new object[] { obj1, this.DisplayType }));
}
return DBNull.Value;
}
return obj1;
}
return base.ParseFormattedValueInternal(this.ValueType, formattedValue, cellStyle, formattedValueTypeConverter, valueTypeConverter);
}
internal object ParseFormattedValueInternal(Type valueType, object formattedValue, DataGridViewCellStyle cellStyle, TypeConverter formattedValueTypeConverter, TypeConverter valueTypeConverter)
{
if (cellStyle == null)
{
throw new ArgumentNullException("cellStyle");
}
if (this.FormattedValueType == null)
{
throw new FormatException(SR.GetString("DataGridViewCell_FormattedValueTypeNull"));
}
if (valueType == null)
{
throw new FormatException(SR.GetString("DataGridViewCell_ValueTypeNull"));
}
if ((formattedValue == null) || !this.FormattedValueType.IsAssignableFrom(formattedValue.GetType()))
{
throw new ArgumentException(SR.GetString("DataGridViewCell_FormattedValueHasWrongType"), "formattedValue");
}
return Formatter.ParseObject(formattedValue, valueType, this.FormattedValueType, (valueTypeConverter == null) ? this.ValueTypeConverter : valueTypeConverter, (formattedValueTypeConverter == null) ? this.FormattedValueTypeConverter : formattedValueTypeConverter, cellStyle.FormatProvider, cellStyle.NullValue, cellStyle.IsDataSourceNullValueDefault ? Formatter.GetDefaultDataSourceNullValue(valueType) : cellStyle.DataSourceNullValue);
}
在方法ParseFormattedValueInternal 里有一个属性: this.FormattedValueType 是字符串型,而我传进去的已经变成了对象型了,所以在这里报错了。
属性 FormattedValueType覆盖了基类, 这里已经变成了字符串类型
public override Type FormattedValueType
{
get
{
return DataGridViewComboBoxCell.defaultFormattedValueType;
}
}
{
get
{
return DataGridViewComboBoxCell.defaultFormattedValueType;
}
}
这个defaultFormattedValueType值就不知从哪里设来的了。 然而基类 FormattedValueType类里的this.ValueType而反是我需要的对象的类型。
[Browsable(false)]
public virtual Type FormattedValueType
{
get
{
return this.ValueType;
}
}
于是用这个基类 里 FormattedValueType重新覆盖。结果错误是没有了,可下拉列表列全是空白。不过我点击下拉列表,却是程序需要的选择。看来显示又出现了问题.
最后的解决方法是:BizObject 是我对象的基类
public override object ParseFormattedValue(object formattedValue, DataGridViewCellStyle cellStyle, TypeConverter formattedValueTypeConverter, TypeConverter valueTypeConverter)
{
ComboBox comboBox = base.DataGridView.EditingControl as ComboBox;
formattedValue = (BizObject)comboBox.SelectedItem;
return formattedValue;
}
{
ComboBox comboBox = base.DataGridView.EditingControl as ComboBox;
formattedValue = (BizObject)comboBox.SelectedItem;
return formattedValue;
}
虽然没有问题了,但是直接反回而忽略其它几个参数,感觉不是很自然。不知大家有没有更好的方法。