You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.29 07:06:10