C# DataGridView绑定BindingList时清空decimal类型单元格抛出DBNull转换异常的解决方案咨询
我之前也碰到过这个一模一样的坑!问题出在:当你清空单元格时,DataGridView会默认把空输入转换成DBNull.Value,然后尝试推送给绑定的decimal类型属性——而decimal是值类型,不能接受DBNull,所以就炸了。你在CellValidating里设置绑定对象的属性值没问题,但这个操作和DataGridView内部的推送逻辑是两条线,它还是会按自己的解析结果去推值,所以异常还是会触发。
最直接的解决方案:用CellParsing事件拦截转换
CellParsing事件是在DataGridView把用户输入的字符串转换成绑定类型之前触发的,这里是最适合拦截空输入的地方,直接把空字符串转成0m,这样后续就不会产生DBNull了。
给你写个具体的代码示例:
private void YourDataGridView_CellParsing(object sender, DataGridViewCellParsingEventArgs e) { // 先确认是目标decimal列,且用户输入为空 if (e.ColumnIndex == YourDecimalColumn.Index && string.IsNullOrWhiteSpace(e.Value?.ToString())) { // 将解析后的值替换为0m e.Value = 0m; // 标记已经完成解析,不用走默认逻辑 e.ParsingApplied = true; } }
这个方法的好处是不用修改绑定对象的属性类型,完全在DataGridView层面解决问题。
另一种方案:改用可空decimal(decimal?)作为绑定属性
如果你能修改绑定对象的属性类型,可以把decimal改成decimal?,然后在属性的setter里处理null的情况:
private decimal? _decimalValue; public decimal? DecimalValue { get => _decimalValue; set { // 如果传入null,自动转为0 _decimalValue = value ?? 0; // 如果实现了INotifyPropertyChanged,记得触发通知 OnPropertyChanged(nameof(DecimalValue)); } }
这样当DataGridView推送DBNull时,会被自动转换成null,然后属性setter把它变成0,同时你的CellFormatting逻辑依然可以正常显示空字符串(因为值是0)。
为什么CellValidating里的处理没用?
CellValidating主要是用来验证输入的合法性,虽然你可以在这里修改绑定对象的属性,但DataGridView的内部值推送逻辑还是会基于它自己解析出来的DBNull去尝试设置属性,所以异常还是会在这个过程中抛出。而CellParsing是在解析阶段就把值改成了合法的decimal类型,从根源上避免了转换问题。
你之前设置dataGridView[e.ColumnIndex, e.RowIndex].Value = 0m;没用,是因为这个操作是在单元格已经尝试解析之后做的,太晚了。
内容的提问来源于stack exchange,提问作者Jimmy

