DataGrid的CollectionChanged事件循环修改字段后新增数据返回空值问题
问题根因分析
- 直接调用
AddRange(e.NewItems.Cast<PI_FitupRep>())时,你添加的是绑定集合中已经被DataGrid填充完字段的实体对象,这些对象本身字段值完整,只要触发保存就能正常写入数据库。 - 遍历新建对象的写法存在三个典型问题:
- 触发时机错误:DataGrid的
CollectionChanged的Add动作会在新行刚创建、用户还未完成输入时就触发,此时读取item.Fitup大概率是空值,会直接被你的非空判断拦截,根本不会执行Add逻辑。 - 实体跟踪不同步:你新建了
PI_FitupRep对象添加到EF上下文,但原绑定集合RepList中存储的还是事件参数里的旧对象,EF保存后生成的主键等返回值只会赋值给你新建的对象,原集合里的旧对象自然会返回null。 - 如果你没有在事件逻辑末尾调用
db.SaveChanges(),所有修改只会停留在EF上下文缓存中,不会真正同步到数据库。
- 触发时机错误:DataGrid的
解决方法
两种可行实现方案,按需选择即可:
方案1:直接修改原集合对象(推荐,逻辑最简洁)
private void RepList_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e) { switch (e.Action) { case NotifyCollectionChangedAction.Add: foreach (PI_FitupRep item in e.NewItems.Cast<PI_FitupRep>()) { // 直接给原对象赋值,不需要新建实体 item.Unit = "4551"; item.FDate = DateTime.Now; if (!string.IsNullOrEmpty(item.Fitup)) { db.PI_FitupReps.Add(item); } } // 按需调用保存,若全局有统一保存逻辑可删除 db.SaveChanges(); break; case NotifyCollectionChangedAction.Remove: db.PI_FitupReps.RemoveRange(e.OldItems.Cast<PI_FitupRep>()); db.SaveChanges(); break; case NotifyCollectionChangedAction.Replace: db.PI_FitupReps.AttachRange(e.OldItems.Cast<PI_FitupRep>()); db.SaveChanges(); break; } }
方案2:必须新建实体时,同步更新绑定集合
private void RepList_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e) { // 先取消事件订阅,避免修改集合时重复触发事件 RepList.CollectionChanged -= RepList_CollectionChanged; try { switch (e.Action) { case NotifyCollectionChangedAction.Add: var addItems = e.NewItems.Cast<PI_FitupRep>().ToList(); foreach (var oldItem in addItems) { // 先移除集合里的临时旧对象 RepList.Remove(oldItem); if (!string.IsNullOrEmpty(oldItem.Fitup)) { var newRep = new PI_FitupRep { Fitup = oldItem.Fitup, Unit = "4551", FDate = DateTime.Now }; db.PI_FitupReps.Add(newRep); // 把EF跟踪的新对象回写到绑定集合,前端就能拿到保存后的返回值 RepList.Add(newRep); } } db.SaveChanges(); break; case NotifyCollectionChangedAction.Remove: db.PI_FitupReps.RemoveRange(e.OldItems.Cast<PI_FitupRep>()); db.SaveChanges(); break; case NotifyCollectionChangedAction.Replace: db.PI_FitupReps.AttachRange(e.OldItems.Cast<PI_FitupRep>()); db.SaveChanges(); break; } } finally { // 恢复事件订阅 RepList.CollectionChanged += RepList_CollectionChanged; } }
额外优化建议
如果你的DataGrid支持行内编辑,建议把赋值、保存逻辑移到RowEditEnding这类行编辑结束事件中触发,不要在CollectionChanged里处理,可完全避免新行未输入完成就触发逻辑的问题。
内容的提问来源于stack exchange,提问作者hamid mosavi
相关产品推荐
相关产品推荐

