DevExpress Grid控件按Tab键时抛出空引用异常求助
解决Grid验证后失焦按Tab触发空引用异常的问题
我来帮你梳理下这个DevExpress GridView里的棘手问题:在RepositoryItemTextEdit完成验证并赋值对象后,行和单元格莫名失焦,此时按Tab键直接触发Object reference not set to an instance of an object异常,但手动重新选中单元格后操作又正常。结合你的代码和异常堆栈,我来分析下原因并给出解决方案。
问题根源分析
从错误堆栈能看到,异常出现在DevExpress.XtraGrid.Views.Grid.GridView.MoveNextCell()方法里——这说明当Tab键尝试切换单元格时,GridView找不到有效的焦点行/单元格,所以抛出了空引用。
你的验证逻辑里直接给TextEdit.EditValue赋值了复杂对象(Partitario),这个操作会触发GridView的行数据更新,间接打乱了控件的焦点状态;另外弹窗选择后的赋值操作是在委托里执行的,此时验证事件的上下文已经结束,控件焦点状态早已脱节。
解决方案
尝试以下几个步骤修复这个问题:
1. 赋值后强制恢复焦点
在给EditValue赋值完成后,手动让GridView重新聚焦到当前单元格,确保Tab键操作有明确的目标:
// 赋值完成后添加以下代码 gridView.FocusedRowHandle = gridView.FocusedRowHandle; gridView.FocusedColumn = gridView.FocusedColumn; gridView.ShowEditor(); // 重新激活单元格编辑器
2. 优化弹窗委托的执行逻辑
弹窗关闭后的赋值操作要放在UI线程上下文里执行,避免直接修改验证事件的e.Cancel状态(委托执行时验证上下文已结束):
form.FnOk += delegate (object item) { if (item is Partitario part) { this.Invoke(new Action(() => { gridView.SetFocusedRowCellValue(gridView.FocusedColumn, part); gridView.ShowEditor(); })); } };
3. 增加空值判断避免潜在异常
给sender转TextEdit、EditValue转字符串的操作都加上空值判断,提前拦截可能的空引用:
var textEdit = sender as TextEdit; if (textEdit == null) return; var codice = textEdit.EditValue?.ToString(); if(string.IsNullOrEmpty(codice)) { e.Cancel = true; return; }
完整修改后的代码示例
private void OnRepositoryPartitariValidating(object sender, CancelEventArgs e) { // 提前记录当前焦点状态 var focusedRow = gridView.FocusedRowHandle; var focusedCol = gridView.FocusedColumn; var textEdit = sender as TextEdit; if (textEdit == null) return; var objConto = gridView.GetFocusedRowCellValue("Conto"); if (textEdit.EditValue is Partitario) return; var codice = textEdit.EditValue?.ToString(); if(string.IsNullOrEmpty(codice)) { e.Cancel = true; return; } var partitario = Partitario.Manager.GetByCodice(codice); if (partitario == null) { e.Cancel = true; var form = objConto is Conto ? new ListPartitari((Conto)objConto) : new ListPartitari(); form.FnOk += delegate (object item) { if (item is Partitario part) { this.Invoke(new Action(() => { gridView.SetFocusedRowCellValue(focusedCol, part); gridView.FocusedRowHandle = focusedRow; gridView.FocusedColumn = focusedCol; gridView.ShowEditor(); })); } }; form.ShowDialog(this); } else { textEdit.EditValue = partitario; // 恢复焦点状态 gridView.FocusedRowHandle = focusedRow; gridView.FocusedColumn = focusedCol; gridView.ShowEditor(); //if (partitario.Conto.Id != ((Conto)objConto).Id) // gridView.SetFocusedRowCellValue("Conto", partitario.Conto); } }
额外提示
- 尽量减少在验证事件中执行数据库查询这类耗时操作,必要时可以用异步加载避免UI卡顿;
- 如果后续还要更新关联列(比如注释里的
Conto列),建议放在GridView.CellValueChanged事件里执行,不要在验证事件中处理,进一步降低对焦点状态的干扰。
内容的提问来源于stack exchange,提问作者k1dev
相关产品推荐
相关产品推荐

