You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

DataGrid的CollectionChanged事件循环修改字段后新增数据返回空值问题

问题根因分析

  • 直接调用AddRange(e.NewItems.Cast<PI_FitupRep>())时,你添加的是绑定集合中已经被DataGrid填充完字段的实体对象,这些对象本身字段值完整,只要触发保存就能正常写入数据库。
  • 遍历新建对象的写法存在三个典型问题:
    • 触发时机错误:DataGrid的CollectionChanged的Add动作会在新行刚创建、用户还未完成输入时就触发,此时读取item.Fitup大概率是空值,会直接被你的非空判断拦截,根本不会执行Add逻辑。
    • 实体跟踪不同步:你新建了PI_FitupRep对象添加到EF上下文,但原绑定集合RepList中存储的还是事件参数里的旧对象,EF保存后生成的主键等返回值只会赋值给你新建的对象,原集合里的旧对象自然会返回null。
    • 如果你没有在事件逻辑末尾调用db.SaveChanges(),所有修改只会停留在EF上下文缓存中,不会真正同步到数据库。

解决方法

两种可行实现方案,按需选择即可:

方案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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.25 03:24:03