DataTable.NewRow()新建行BindingManager.Position访问异常
问题原因分析
新增行后bindingManager.Position赋值后始终为0
你从BindingContext获取到的bindingManager实际是CurrencyManager类型,它并不直接关联DataTable.Rows集合,而是关联DataTable对应的默认DataView对象,维护的可导航行列表会受视图行状态过滤、列表更新时机影响:
- 你断点看到的
dataTable.Rows.Count == 11是DataTable层面的总行数,不代表绑定上下文识别到的可导航行数,此时bindingManager.Count实际仍为10——刚通过NewRow()添加的行状态为Added,如果没有主动刷新绑定列表、或视图配置未允许展示新增行,这行不会被纳入CurrencyManager的可导航索引范围。 - 此时给Position赋值10(即11-1)已经超出了绑定列表的最大有效索引(最大为9),CurrencyManager会自动将非法的Position值重置为0,所以赋值始终不生效。
重新绑定Copy后的DataTable时,Position变化但始终显示同一行
问题出在你的重新绑定逻辑:执行BindTextBoxsAgainWith时,你没有先清除TextBox控件上残留的旧数据绑定,导致每个TextBox上同时叠加了两套绑定规则:一套指向最初的旧DataTable实例,一套指向Copy出来的新DataTable实例。
这种情况下Position变更触发的绑定更新会被旧绑定规则拦截,始终拉取旧数据源中固定位置的行数据,看起来就像无论怎么切换Position都显示同一行。
修复方案
- 不需要通过Copy表、重新绑定的方式实现新增行跳转,直接在原绑定逻辑上调整即可:
DataTable dataTable = dataBase.ReadTable(tableName); // 显式转成CurrencyManager类型方便操作 CurrencyManager bindingManager = (CurrencyManager)BindingContext[dataTable]; // 配置绑定关联的视图允许新增行展示 DataView bindView = (DataView)bindingManager.List; bindView.AllowNew = true; BindTextBoxsWith(dataTable); ActionToChange(bindingManager.Position); // 新增行逻辑 DataRow dataRow = dataTable.NewRow(); dataRow[primaryKey] = 0; dataTable.Rows.Add(dataRow); // 刷新绑定列表确保新增行被纳入 bindingManager.Refresh(); // 必须用bindingManager.Count计算新行索引,不要直接用dataTable.Rows.Count bindingManager.Position = bindingManager.Count - 1;
- 如果确实需要替换数据源重新绑定,绑定前必须先清除控件上的旧绑定,避免多套绑定冲突:
// 遍历清除所有TextBox的原有数据绑定 foreach (Control ctrl in Controls) { if (ctrl is TextBox tb) { tb.DataBindings.Clear(); } } // 再执行新数据源的绑定逻辑 dataTable = dataTable.Copy(); BindTextBoxsWith(dataTable); bindingManager = BindingContext[dataTable];
注意:所有绑定导航相关的索引、行数判断,都要以
bindingManager.Count为准,不要直接依赖DataTable.Rows.Count,在存在视图筛选、行状态过滤、未提交编辑行的场景下,二者数值不一定一致。
内容的提问来源于stack exchange,提问作者Forever Demornov
相关产品推荐
相关产品推荐

