在datagridview批量更新时如何跳过未触发编辑的行?
方案1:无数据源绑定场景(自行维护编辑行集合,稳定性最高)
这种方式不管你有没有给DataGridView绑定数据源都可以用,不会受控件排序、刷新等操作的影响。
- 先在窗体类中定义一个全局的哈希集合,用来存储已编辑行的索引:
// 定义在窗体类内部,方法外 private HashSet<int> _editedRowIndexSet = new HashSet<int>();
- 给
dgViewTask绑定CellEndEdit事件,只要用户完成单元格编辑就把行索引加入集合:
private void dgViewTask_CellEndEdit(object sender, DataGridViewCellEventArgs e) { // 排除表头行和空白新增行 if (e.RowIndex >= 0 && !dgViewTask.Rows[e.RowIndex].IsNewRow) { _editedRowIndexSet.Add(e.RowIndex); } }
如果你的业务允许用户删除行,建议同时绑定UserDeletingRow事件,避免后续遍历到已删除的行索引报错:
private void dgViewTask_UserDeletingRow(object sender, DataGridViewRowCancelEventArgs e) { _editedRowIndexSet.Remove(e.Row.Index); }
- 替换原来的全量遍历逻辑,只遍历已编辑的行:
int totalAffected = 0; // 只遍历修改过的行 foreach (int rowIdx in _editedRowIndexSet) { DataGridViewRow currentRow = frm1.dgViewTask.Rows[rowIdx]; if (frm1.btnMLA.Enabled == false) { objNPTBEL.reportingDate = reportingDate.ToString(); objNPTBEL.startDate = startDate.ToString(); objNPTBEL.endDate = endDate.ToString(); } else { objNPTBEL.reportingDate = reportingDate1.ToString(); objNPTBEL.startDate = estStartDate.ToString(); objNPTBEL.endDate = estEndDate.ToString(); } objNPTBEL.id = Convert.ToInt32(currentRow.Cells[0].Value); objNPTBEL.taskname = currentRow.Cells[4].Value.ToString(); objNPTBEL.remarks = currentRow.Cells[5].Value.ToString(); int curRes = objNPTBLL.NonProcessingTime(9, objNPTBEL.id, objNPTBEL.workdayID, objNPTBEL.taskname, objNPTBEL.reportingDate, objNPTBEL.remarks, objNPTBEL.startDate, objNPTBEL.endDate, null, null, objNPTBEL.eststartDate, objNPTBEL.estendDate, null, objNPTBEL.estreportingDate, null, null, objNPTBEL.rationale); if(curRes > 0) totalAffected++; } // 保存完成后清空集合,下次编辑重新收集 _editedRowIndexSet.Clear(); if (totalAffected > 0) { MessageBox.Show("更新成功", "DigiTrack", MessageBoxButtons.OK, MessageBoxIcon.Information); frm1.RefreshdgViewTask(); frm1.clearVariable(); this.Hide(); }
方案2:绑定了DataTable数据源场景(代码量最少)
如果你给DataGridView绑定的数据源是DataTable,直接用DataTable自带的行状态筛选即可,不需要额外监听事件:
DataTable sourceDt = (DataTable)frm1.dgViewTask.DataSource; // 筛选出所有已修改的行 DataRow[] modifiedRows = sourceDt.Select("", "", DataViewRowState.ModifiedCurrent); int totalAffected = 0; foreach (DataRow dr in modifiedRows) { // 直接从DataRow取字段值即可,不用读取控件单元格 if (frm1.btnMLA.Enabled == false) { objNPTBEL.reportingDate = reportingDate.ToString(); objNPTBEL.startDate = startDate.ToString(); objNPTBEL.endDate = endDate.ToString(); } else { objNPTBEL.reportingDate = reportingDate1.ToString(); objNPTBEL.startDate = estStartDate.ToString(); objNPTBEL.endDate = estEndDate.ToString(); } objNPTBEL.id = Convert.ToInt32(dr[0]); objNPTBEL.taskname = dr[4].ToString(); objNPTBEL.remarks = dr[5].ToString(); int curRes = objNPTBLL.NonProcessingTime(9, objNPTBEL.id, objNPTBEL.workdayID, objNPTBEL.taskname, objNPTBEL.reportingDate, objNPTBEL.remarks, objNPTBEL.startDate, objNPTBEL.endDate, null, null, objNPTBEL.eststartDate, objNPTBEL.estendDate, null, objNPTBEL.estreportingDate, null, null, objNPTBEL.rationale); if(curRes > 0) totalAffected++; } // 重置行状态,下次修改会重新标记为Modified sourceDt.AcceptChanges();
临时兼容方案
如果不想改动太多现有代码,可以直接在原有循环的最开头加一行判断,跳过未修改的行,不过这种方式的行状态可能会被控件排序、刷新等操作重置,适合临时使用:
for (int i = 0; i < frm1.dgViewTask.Rows.Count; i++) { // 新增这一行,跳过未修改的行 if (!frm1.dgViewTask.Rows[i].Modified) continue; // 原有逻辑不变 }
内容的提问来源于stack exchange,提问作者user12366709
相关产品推荐
相关产品推荐

