根本原因是List未实现INotifyPropertyChanged或IBindingList,导致界面不自动更新;应改用BindingList并确保T类属性可写、支持通知,新增行需处理DefaultValuesNeeded事件,删除需同步数据库,编辑后须离开单元格才提交。

DataGridView绑定List后修改不自动更新界面?
根本原因是ListdataGridView1.DataSource = list只能单向显示,改list[i].Name不会刷新单元格。
实操建议:
- 改用
BindingList<t></t>替代List<t></t>,它实现了IBindingList,支持添加/删除时触发事件 -
T类的每个属性必须是public set,且最好也实现INotifyPropertyChanged(否则编辑单元格后按回车,对象属性已变但其他地方读不到最新值) - 不要手动调用
Refresh()或Update()——这些对绑定无效;改完数据后确保触发了属性变更通知
点击新增行时自动创建对象但保存失败?
DataGridView默认允许用户在最后一行输入新数据,但BindingList<t></t>不会自动为你new对象,你得拦截DefaultValuesNeeded事件。
常见错误现象:NullReferenceException出现在新增行编辑后点其他行——因为那一行底层对象还是null。
实操建议:
- 订阅
dataGridView1.DefaultValuesNeeded事件,在事件里用e.Row.Cells["Name"].Value = ""等预填默认值,并确保e.Row.DataBoundItem被设为一个新实例(如e.Row.DataBoundItem = new Person()) - 如果用了
BindingSource,记得把AllowNew设为true,否则新增行根本不会出现 - 别依赖
RowsAdded事件来初始化对象——它触发太晚,用户可能已经输了一半内容
删除行后数据库没同步,甚至删错数据?
DataGridView本身不负责持久化,删掉的是内存里的对象,不是数据库记录。很多人直接调用bindingList.Remove(item)就以为完事了。
使用场景:你有本地缓存+远程数据库,需要先删DB再删内存,或反过来。
实操建议:
- 在
UserDeletingRow事件里取消删除(e.Cancel = true),转而弹窗确认,再执行数据库DELETE语句 - 删成功后再调用
bindingList.Remove(item),避免UI和DB状态不一致 - 注意:如果用
BindingSource,删的是BindingSource.Current,不是dataGridView1.CurrentRow.DataBoundItem——后者可能为空(比如焦点在新增行)
编辑后调用Update()却提示“动态SQL生成失败”?
这是SqlDataAdapter.Update()报的错,说明你没配好InsertCommand/UpdateCommand,或者DataTable的RowState没正确标记。
性能影响:每次Update都全量提交所有变更,大数据量时很慢;而且如果没设主键,SqlCommandBuilder无法自动生成UPDATE语句。
实操建议:
- 用
SqlCommandBuilder前,确保DataTable的PrimaryKey已设置(对应数据库主键列) - 别直接把
BindingList<t></t>扔给SqlDataAdapter——它只认DataTable或DataSet;得先把变更同步回DataTable(比如监听BindingList.ListChanged事件) - 更稳的做法是绕过DataSet:遍历
bindingList,对item.RowState == Modified的对象手写参数化UPDATE语句
最易被忽略的一点:DataGridView的编辑模式下,用户改完单元格必须离开该行(比如Tab到下一行或Enter),才会触发CellValueChanged并更新绑定对象——光在格子里打字不等于数据已落库。


















