ASP.NET GridView动态新增行后删除行索引不匹配问题
现有删除逻辑的问题点
- 单元格索引错误:
OnRowDataBound方法中查找删除按钮时使用了Cells[2],但删除命令列是第5列(从0开始计数对应索引为4),Cells[2]是第二列输入框所在单元格,根本找不到删除按钮,确认弹窗逻辑完全不生效。 - DataRow删除操作不完整:调用
DataRow.Delete()方法仅会将行状态标记为Deleted,不会真正从行集合中移除,若不调用AcceptChanges()提交更改,后续绑定、遍历行时会出现数据异常、索引越界问题。 - 删除后的数据同步逻辑完全错误:删除目标行后,GridView尚未重新绑定,行集合还是删除前的状态,此时从被删行的索引开始倒序遍历行、执行
rowIndex--,既无法正确将剩余行的输入值同步回DataTable,还会出现负数索引的运行时错误。 - 行号与计数未同步:删除行后没有重新编排剩余行的序号,也没有更新Session中存储的行计数,后续新增行时会出现行号重复的问题。
- 未做删空保护:如果用户把所有行都删掉,后续新增行、绑定数据时会触发空引用错误。
修正后的代码
首先修正行绑定事件的逻辑:
protected void OnRowDataBound(object sender, GridViewRowEventArgs e) { if (e.Row.RowType == DataControlRowType.DataRow) { string rowNum = e.Row.Cells[0].Text; // 修正单元格索引,删除按钮位于索引4的单元格 foreach (Button button in e.Row.Cells[4].Controls.OfType<Button>()) { if (button.CommandName == "Delete") { button.Attributes["onclick"] = $"if(!confirm('确定要删除第 {rowNum} 行吗?')){{ return false; }};"; } } } }
然后重写删除事件逻辑,按照「先同步现有输入→再执行删除→提交更改→补全空状态→重排行号→更新计数→重新绑定」的流程处理:
protected void OnRowDeleting(object sender, GridViewDeleteEventArgs e) { if (ViewState["CurrentTable"] == null) return; DataTable dtCurrentTable = (DataTable)ViewState["CurrentTable"]; int deleteIndex = e.RowIndex; // 先同步当前所有行的输入值到DataTable,避免删除操作丢失已填写内容 for (int i = 0; i < Gridview1.Rows.Count; i++) { TextBox box1 = (TextBox)Gridview1.Rows[i].Cells[1].FindControl("TextBox1"); TextBox box2 = (TextBox)Gridview1.Rows[i].Cells[2].FindControl("TextBox2"); TextBox box3 = (TextBox)Gridview1.Rows[i].Cells[3].FindControl("TextBox3"); dtCurrentTable.Rows[i]["Column1"] = box1.Text; dtCurrentTable.Rows[i]["Column2"] = box2.Text; dtCurrentTable.Rows[i]["Column3"] = box3.Text; } // 执行删除并提交更改 if (dtCurrentTable.Rows.Count > deleteIndex) { dtCurrentTable.Rows[deleteIndex].Delete(); dtCurrentTable.AcceptChanges(); } // 删空时自动补1行初始行,避免后续操作报错 if (dtCurrentTable.Rows.Count == 0) { DataRow newDr = dtCurrentTable.NewRow(); newDr["RowNumber"] = 1; newDr["Column1"] = string.Empty; newDr["Column2"] = string.Empty; newDr["Column3"] = string.Empty; dtCurrentTable.Rows.Add(newDr); } // 重新编排剩余行的行号,同步更新行计数 for (int i = 0; i < dtCurrentTable.Rows.Count; i++) { dtCurrentTable.Rows[i]["RowNumber"] = i + 1; } count = dtCurrentTable.Rows.Count; Session["count"] = count; // 持久化数据并重新绑定 ViewState["CurrentTable"] = dtCurrentTable; Gridview1.DataSource = dtCurrentTable; Gridview1.DataBind(); SetPreviousData(); }
额外优化建议
- 原有
AddNewRowToGrid方法中存在一行冗余代码:Label label1 = (Label)Gridview1.Rows[rowIndex].Cells[0].FindControl("Label1");,第一列是BoundField,不存在ID为Label1的控件,这行代码始终返回null,建议直接删除。 - 由于同步输入的逻辑在新增、删除时都要用到,可以把「遍历GridView行同步值到DataTable」的逻辑抽成独立方法,减少重复代码。
内容的提问来源于stack exchange,提问作者user8512043
相关产品推荐
相关产品推荐

