C# WinForms中DataGridView与TextBox绑定DataTable更新异常问题
问题解决方法
核心问题分析
直接将DataTable作为控件数据源时,单元格编辑过程中的数据变更通知无法有效传递到TextBox;同时CellValidating事件触发时机过早,手动调用EndEdit()容易导致数据同步不完整,这就是TextBox无法更新的原因。
具体解决方案
1. 引入BindingSource作为中间层
BindingSource会自动处理数据变更的事件通知,确保所有绑定控件同步感知数据源变化,是WinForms数据绑定的标准最佳实践。
2. 改用CellEndEdit事件处理逻辑
替换CellValidating为CellEndEdit事件,该事件在单元格编辑完全结束、值已提交到数据源后触发,无需手动调用EndEdit(),避免时机问题。
修改后的完整代码
using System; using System.Data; using System.Windows.Forms; namespace TESTING { public partial class Form2 : Form { private DataTable dt = new DataTable(); // 添加BindingSource成员 private BindingSource bs = new BindingSource(); public Form2() { InitializeComponent(); dt.Columns.Add("Field1", typeof(string)); dt.Columns.Add("Field2", typeof(string)); dt.Columns.Add("Field3", typeof(string)); dataGridView1.AllowUserToAddRows = false; dataGridView1.AutoGenerateColumns = false; // 将BindingSource作为DataGridView的数据源 bs.DataSource = dt; dataGridView1.DataSource = bs; dataGridView1.Columns["Column1"].DataPropertyName = "Field1"; dataGridView1.Columns["Column2"].DataPropertyName = "Field2"; textBox1.DataBindings.Clear(); // TextBox绑定到BindingSource的Field3 textBox1.DataBindings.Add("Text", bs, "Field3"); dt.Rows.Add(); } // 替换为CellEndEdit事件 private void dataGridView1_CellEndEdit(object sender, DataGridViewCellEventArgs e) { switch (dataGridView1.Columns[e.ColumnIndex].Name) { case "Column1": var currentRow = dt.Rows[e.RowIndex]; if (currentRow["Field1"].ToString().Trim() == "123") { currentRow["Field2"] = "123-Column2"; currentRow["Field3"] = "123-Column3"; } break; } } protected override bool ProcessCmdKey(ref System.Windows.Forms.Message msg, System.Windows.Forms.Keys keyData) { int icolumn = dataGridView1.CurrentCell.ColumnIndex; int irow = dataGridView1.CurrentCell.RowIndex; if (keyData == Keys.Enter) { if (icolumn < dataGridView1.Columns.Count - 1) dataGridView1.CurrentCell = dataGridView1[icolumn + 1, irow]; else dataGridView1.CurrentCell = dataGridView1[0, irow]; return true; } else return base.ProcessCmdKey(ref msg, keyData); } private void button1_Click(object sender, EventArgs e) { dt.Rows[0]["Field1"] = "123"; dt.Rows[0]["Field2"] = "123-Column2"; dt.Rows[0]["Field3"] = "123-Column3"; } } }
额外说明
- 不需要再调用
this.Refresh(),BindingSource会自动通知所有绑定控件更新。 - 如果必须保留
CellValidating事件(比如需要做输入验证),则需要确保在修改数据源后,调用bs.ResetCurrentItem()来手动触发当前行的变更通知,代码示例:
private void dataGridView1_CellValidating(object sender, DataGridViewCellValidatingEventArgs e) { switch (dataGridView1.Columns[e.ColumnIndex].Name) { case "Column1": // 先完成编辑提交 if (!dataGridView1.EndEdit()) return; var currentRow = dt.Rows[e.RowIndex]; if (currentRow["Field1"].ToString().Trim() == "123") { currentRow["Field2"] = "123-Column2"; currentRow["Field3"] = "123-Column3"; // 手动通知BindingSource更新当前行 bs.ResetCurrentItem(); } break; } }
内容的提问来源于stack exchange,提问作者Potato
相关产品推荐
相关产品推荐

