DataGridView只读单元格更新时触发NullReferenceException问题求助
DataGridView更新只读列时出现NullReferenceException排查
问题场景
DataGridView中部分列设置为只读,但需要通过代码更新这些单元格的值;该控件的数据源是合并三个不同表的DataTable。当收到电报消息触发更新操作时,偶尔会出现NullReferenceException错误,不确定是否因更新只读单元格导致,附上相关代码求排查。
原代码
private void UpdateTrialSeqValue(string strProduct, string strBuy, string strSell, string strBuy1Qty, string strSell1Qty) { if (!this.IsDisposed && dgvWSettingAll != null) { if (this.InvokeRequired) { BeginInvoke(new MethodInvoker(() => UpdateTrialSeqValue(strProduct, strBuy, strSell, strBuy1Qty, strSell1Qty))); return; } lock (Update_Flag) { foreach (DataGridViewRow row in dgvSettingAll.Rows) { if(row.Index >= 0) { string product = Convert.ToString(row.Cells["Colproduct"].Value); if (product == strProduct) { row.Cells["ColBuyQty"].Value = strBuy1Qty; row.Cells["ColBuyPrice"].Value = strBuy; row.Cells["ColSellPrice"].Value = strSell; row.Cells["ColSellQty"].Value = strSell1Qty; } } } } } }
可能的原因及解决方案
1. 单元格/行对象为空引发空引用
遍历dgvSettingAll.Rows时,可能存在未初始化的空行(比如控件自动生成的新行),导致row.Cells["Colproduct"]或目标单元格对象为null,访问其Value属性时触发异常。
解决方法:
- 跳过新行:增加
if (row.IsNewRow) continue;判断 - 访问单元格前先检查对象是否为null
2. 只读列的更新限制混淆
DataGridView列设置ReadOnly=true仅禁止用户手动编辑,代码层面直接赋值是允许的;但如果绑定的DataTable对应列也设置了ReadOnly=true,则会导致赋值失败甚至报错。
解决方法:
- 检查绑定的DataTable中目标列的
ReadOnly属性,确保代码可修改 - 优先更新数据源DataTable而非直接操作DataGridView单元格(绑定模式下更规范,避免控件与数据源状态不一致)
3. 多线程锁对象无效
lock (Update_Flag)的锁对象如果不是静态全局唯一的,会导致并发更新时无法互斥,引发对象状态异常。
解决方法:
- 将
Update_Flag定义为静态私有对象:private static readonly object Update_Flag = new object();
4. 参数或值为空的处理缺失
传入的参数或赋值内容为null时,虽然Convert.ToString能处理null,但直接赋值给单元格可能引发数据源兼容性问题(比如DataTable列不允许null)。
解决方法:
- 赋值时将null转换为
DBNull.Value,适配数据源要求
优化后的代码示例
// 确保锁对象静态唯一,避免并发冲突 private static readonly object Update_Flag = new object(); private void UpdateTrialSeqValue(string strProduct, string strBuy, string strSell, string strBuy1Qty, string strSell1Qty) { if (this.IsDisposed || dgvSettingAll == null) return; if (this.InvokeRequired) { BeginInvoke(new MethodInvoker(() => UpdateTrialSeqValue(strProduct, strBuy, strSell, strBuy1Qty, strSell1Qty))); return; } lock (Update_Flag) { foreach (DataGridViewRow row in dgvSettingAll.Rows) { // 跳过未初始化的新行 if (row.IsNewRow) continue; // 检查目标单元格是否存在 var productCell = row.Cells["Colproduct"]; if (productCell == null) continue; string product = Convert.ToString(productCell.Value); // 用不区分大小写的匹配避免字符串大小写问题 if (string.Equals(product, strProduct, StringComparison.OrdinalIgnoreCase)) { // 封装单元格更新逻辑,增加空判断和只读处理 UpdateCellValue(row, "ColBuyQty", strBuy1Qty); UpdateCellValue(row, "ColBuyPrice", strBuy); UpdateCellValue(row, "ColSellPrice", strSell); UpdateCellValue(row, "ColSellQty", strSell1Qty); // 更推荐的方式:直接更新绑定的DataTable // if (row.DataBoundItem is DataRowView rowView) // { // rowView.Row["ColBuyQty"] = strBuy1Qty ?? DBNull.Value; // rowView.Row["ColBuyPrice"] = strBuy ?? DBNull.Value; // // ...其他列赋值 // } // 找到匹配行后退出循环,提升效率 break; } } } } // 封装单元格更新方法,兼容只读列和空值 private void UpdateCellValue(DataGridViewRow row, string columnName, object value) { var cell = row.Cells[columnName]; if (cell == null) return; // 临时取消只读(如果需要),赋值后恢复 bool wasReadOnly = cell.ReadOnly; if (wasReadOnly) cell.ReadOnly = false; // 处理空值,适配数据源要求 cell.Value = value ?? DBNull.Value; if (wasReadOnly) cell.ReadOnly = true; }
内容的提问来源于stack exchange,提问作者sharon
相关产品推荐
相关产品推荐

