C#中DataGridView的CellValueChanged事件触发时自定义函数不执行如何解决
问题原因分析
- 事件未正确绑定:仅编写了
attendance_dgw_CellValueChanged方法,但没有将方法和控件的CellValueChanged事件关联,导致事件触发时不会执行对应逻辑。 - 死循环导致逻辑中断:
replace_namesSurnames方法中会修改stud_nameSurname列的值,这个修改操作会再次触发CellValueChanged事件,无限递归会导致程序异常或者逻辑被中断。 - 空值/无效值报错:当
student_id列的值为空、不是有效数字时,Convert.ToInt32会抛出异常,导致方法直接终止运行,尤其是DataGridView自带的新行里student_id默认是空值,非常容易触发该问题。 - 编辑未提交不触发事件:默认情况下,单元格输入内容后需要按下回车或者失去焦点才会提交编辑触发
CellValueChanged,如果只是输入完未提交,事件不会触发。
可行修复方案
第一步:确认事件正确绑定
可以选择两种绑定方式:
- 设计器绑定:选中
attendance_dgw控件,在属性面板的事件列表中找到CellValueChanged,选择对应的处理方法即可 - 代码绑定:在窗体构造函数或者
Form_Load初始化逻辑中添加绑定代码:
attendance_dgw.CellValueChanged += attendance_dgw_CellValueChanged;
第二步:优化逻辑避免死循环和报错
修改原有逻辑,仅在student_id列变更时执行更新,同时临时注销事件避免修改姓名列时重复触发事件,增加空值、越界判断避免异常:
private void attendance_dgw_CellValueChanged(object sender, DataGridViewCellEventArgs e) { // 过滤行头、新增空白行,仅处理student_id列的变更 if (e.RowIndex < 0 || e.RowIndex == attendance_dgw.Rows.Count - 1 || attendance_dgw.Columns[e.ColumnIndex].Name != "student_id") { return; } // 临时注销事件,避免修改姓名列时再次触发事件造成死循环 attendance_dgw.CellValueChanged -= attendance_dgw_CellValueChanged; try { UpdateNameSurnameForRow(e.RowIndex); } finally { // 逻辑执行完成后重新绑定事件 attendance_dgw.CellValueChanged += attendance_dgw_CellValueChanged; } } // 单条行更新方法,供事件调用 private void UpdateNameSurnameForRow(int rowIndex) { DataGridViewRow row = attendance_dgw.Rows[rowIndex]; // 空值、格式校验,避免转换报错 if (row.Cells["student_id"].Value == null || !int.TryParse(row.Cells["student_id"].Value.ToString(), out int student_id)) { row.Cells["stud_nameSurname"].Value = string.Empty; return; } // 索引越界校验,避免student_id不存在时报错 if (student_id < 1 || student_id > attendanceRecording.Tables["students"].Rows.Count) { row.Cells["stud_nameSurname"].Value = "无效学号"; return; } string name = attendanceRecording.Tables["students"].Rows[student_id - 1]["student_name"].ToString(); string surname = attendanceRecording.Tables["students"].Rows[student_id - 1]["student_surname"].ToString(); row.Cells["stud_nameSurname"].Value = $"{name} {surname}"; } // 保留原全量更新方法,供初始化、按钮点击场景调用 public void replace_namesSurnames() { attendance_dgw.CellValueChanged -= attendance_dgw_CellValueChanged; try { foreach (DataGridViewRow row in attendance_dgw.Rows) { if (row.Index < attendance_dgw.Rows.Count - 1) { UpdateNameSurnameForRow(row.Index); } } } finally { attendance_dgw.CellValueChanged += attendance_dgw_CellValueChanged; } }
第三步(可选):实现输入即时触发
如果需要输入内容后无需按回车、无需失去焦点就即时更新姓名,可以新增CurrentCellDirtyStateChanged事件绑定,主动提交编辑:
private void attendance_dgw_CurrentCellDirtyStateChanged(object sender, EventArgs e) { if (attendance_dgw.CurrentCell is DataGridViewTextBoxCell && attendance_dgw.Columns[attendance_dgw.CurrentCell.ColumnIndex].Name == "student_id" && attendance_dgw.IsCurrentCellDirty) { attendance_dgw.CommitEdit(DataGridViewDataErrorContexts.Commit); } }
添加完成后同样需要绑定该事件:
attendance_dgw.CurrentCellDirtyStateChanged += attendance_dgw_CurrentCellDirtyStateChanged;
内容的提问来源于stack exchange,提问作者predefined_
相关产品推荐
相关产品推荐

