Xceed DataGrid库EndEdit报错:测试复现与解决方案咨询
Xceed DataGrid EndEdit() 错误:复现与解决方案
我之前在WPF项目里用Xceed DataGrid时也踩过这个坑,刚好能给你详细说说怎么复现这个错误,以及对应的解决办法。
如何复现这个错误
这个错误的核心原因是:你调用EndEdit()时,当前正在编辑的项已经不再属于DataGrid的数据源上下文了。以下是两种常见的复现场景:
场景1:编辑未提交的新行时移除该行
- 准备一个绑定了
ObservableCollection<T>的Xceed DataGrid,实体类实现INotifyPropertyChanged - 手动添加一条新行,点击某个单元格进入编辑状态(不要按回车或点击其他地方完成编辑)
- 通过代码把这条还在编辑中的新行从集合里移除
- 立即调用
myGrid.EndEdit(),此时就会触发那个错误——因为被移除的行已经不在DataGrid的Items里了
你可以用Dispatcher模拟后台异步移除的场景,更贴近用户实际操作:
// 假设myCollection是绑定的ObservableCollection,myGrid是Xceed DataGrid var newItem = new YourEntity(); myCollection.Add(newItem); myGrid.SelectedItem = newItem; myGrid.Focus(); // 模拟用户正在编辑,后台异步移除 Dispatcher.BeginInvoke(DispatcherPriority.Background, new Action(() => { myCollection.Remove(newItem); myGrid.EndEdit(); // 这里会触发目标错误 }));
场景2:编辑现有行时切换数据源
- 编辑DataGrid中某一行的单元格,保持单元格处于激活编辑状态
- 把DataGrid的
ItemsSource切换到另一个集合,或者直接清空原集合 - 调用
myGrid.EndEdit(),同样会触发错误,因为原来的编辑项已经不在新的上下文里了
解决办法
针对这个问题,我们可以从提前处理编辑状态和调用EndEdit前校验上下文两个方向入手:
方案1:调用EndEdit前校验编辑项是否存在
在调用EndEdit()之前,先获取当前正在编辑的项,判断它是否还在DataGrid的Items集合里。如果不在,就取消编辑而不是强制结束:
var activeCell = myGrid.ActiveCell; if (activeCell != null) { var editingItem = activeCell.DataContext; if (myGrid.Items.Contains(editingItem)) { // 项还在集合里,正常结束编辑 myGrid.EndEdit(); } else { // 项已经被移除,取消编辑 myGrid.CancelEdit(); } }
方案2:修改数据源前先处理编辑状态
不管用户有没有完成编辑,在修改数据源(移除项、切换ItemsSource)之前,先提交或取消所有活跃的编辑会话,避免后续调用EndEdit时出错:
// 先提交单元格和行的编辑 myGrid.CommitEdit(DataGridEditingUnit.Cell, true); myGrid.CommitEdit(DataGridEditingUnit.Row, true); // 如果不需要提交编辑内容,也可以直接取消 // myGrid.CancelEdit(DataGridEditingUnit.Cell); // myGrid.CancelEdit(DataGridEditingUnit.Row); // 现在再修改数据源 myCollection.Remove(itemToRemove); // 或者切换ItemsSource // myGrid.ItemsSource = newCollection;
方案3:跟踪编辑状态,提前干预
通过监听DataGrid的编辑事件,维护当前正在编辑的项,在修改数据源时针对性处理:
private object _currentEditingItem; private void MyGrid_BeginningEdit(object sender, DataGridBeginningEditEventArgs e) { _currentEditingItem = e.Row.DataContext; } private void MyGrid_CellEditEnding(object sender, DataGridCellEditEndingEventArgs e) { _currentEditingItem = null; } // 当需要移除元素时 if (_currentEditingItem != null && _currentEditingItem.Equals(itemToRemove)) { // 如果要移除的是正在编辑的项,先取消编辑 myGrid.CancelEdit(); } myCollection.Remove(itemToRemove);
方案4:使用Xceed专属API处理
Xceed DataGrid提供了一些更便捷的API来处理编辑状态,比如CommitAllEdits()可以一次性提交所有未完成的编辑:
// 先尝试提交所有编辑 var commitSuccess = myGrid.CommitAllEdits(); if (!commitSuccess) { // 提交失败的话,取消所有编辑 myGrid.CancelAllEdits(); } // 再进行数据源操作 myCollection.Remove(itemToRemove);
另外,也可以通过myGrid.IsEditing属性判断当前是否处于编辑状态,再做对应处理。
内容的提问来源于stack exchange,提问作者Merta
相关产品推荐
相关产品推荐

