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

GridView PageIndexChanging事件中保存选中行至SQL Server的问题

这个问题我之前也碰到过,核心原因是在PageIndexChanging事件里,你先执行了分页绑定,再去遍历GridView.Rows,这时候拿到的已经是新页的行数据,而不是用户刚才选中的旧页的行。按钮回发时能成功,是因为按钮点击时GridView还没切换页面,Rows还是当前用户操作的那一页的内容。

下面给你一步步的解决方案:

一、先搞懂为什么PageIndexChanging里存不了

当用户点击分页按钮时,页面回发的事件顺序是:

  1. 页面加载并恢复ViewState
  2. 触发PageIndexChanging事件
  3. 你设置GridView.PageIndex = e.NewPageIndex然后DataBind,此时GridView会重新绑定新页的数据,原来旧页的行和选中状态都被覆盖
  4. 你再遍历GridView.Rows,拿到的是新页的未选中行,自然存不了数据

所以正确的顺序应该是:先保存当前页的选中行 → 再执行分页绑定 → 最后把保存的数据存入数据库

二、具体实现步骤

1. 封装GridView绑定方法

把重复的绑定逻辑抽出来,方便复用和维护,同时还能恢复选中状态(可选,提升用户体验):

private void BindGridView()
{
    // 用参数化查询避免SQL注入!
    string query2 = @"select QuestionID, QuestionText, q.QuizID, TopicID 
                      from StandardQuizData qd
                      join Questions q on qd.QuizID = q.QuizID
                      where qd.TopicID = @TopicID";
    
    using (var adapt2 = new SqlDataAdapter(query2, connString))
    {
        // 添加参数,防止SQL注入
        adapt2.SelectCommand.Parameters.AddWithValue("@TopicID", Request.QueryString["UserCustomQuizTopicID"]);
        
        var ds2 = new DataSet();
        adapt2.Fill(ds2, "Questions");
        GridView1.DataSource = ds2;
        GridView1.DataBind();
    }
    
    // 恢复之前保存的选中状态(如果需要)
    RestoreSelectedRowState();
}

2. 保存当前页的选中行数据

在分页前,先把用户选中的行数据存到ViewState(或者Session,根据你的需求):

private void SaveSelectedRows()
{
    DataTable selectedTable = new DataTable();
    // 和你要存入数据库的列保持一致
    selectedTable.Columns.Add("CustomQuizQID", typeof(string));
    selectedTable.Columns.Add("UserID", typeof(string));
    selectedTable.Columns.Add("QuizID", typeof(string));
    selectedTable.Columns.Add("TopicID", typeof(string));
    selectedTable.Columns.Add("QuestionID", typeof(string));
    selectedTable.Columns.Add("QuestionName", typeof(string));
    
    foreach (GridViewRow gvrow in GridView1.Rows)
    {
        var checkbox = gvrow.FindControl("CheckBoxSelect") as CheckBox;
        if (checkbox != null && checkbox.Checked)
        {
            DataRow drow = selectedTable.NewRow();
            drow["UserID"] = User.Identity.GetUserId().ToString();
            drow["QuizID"] = Request.QueryString["UserCustomQuizID"].ToString();
            drow["TopicID"] = gvrow.Cells[0].Text;
            drow["QuestionID"] = gvrow.Cells[1].Text;
            drow["QuestionName"] = gvrow.Cells[2].Text;
            selectedTable.Rows.Add(drow);
        }
    }
    
    // 存到ViewState里,后续可以取用
    ViewState["SelectedRows"] = selectedTable;
}

3. 恢复选中状态(可选)

如果希望用户切换页面后,之前选中的行(如果在当前页)依然保持选中,可以加这个方法:

private void RestoreSelectedRowState()
{
    if (ViewState["SelectedRows"] == null) return;
    
    DataTable selectedTable = (DataTable)ViewState["SelectedRows"];
    foreach (GridViewRow gvrow in GridView1.Rows)
    {
        string currentQuestionID = gvrow.Cells[1].Text;
        // 检查当前行的QuestionID是否在已选中的列表里
        var matchedRow = selectedTable.AsEnumerable()
                                       .FirstOrDefault(r => r["QuestionID"].ToString() == currentQuestionID);
        
        if (matchedRow != null)
        {
            var checkbox = gvrow.FindControl("CheckBoxSelect") as CheckBox;
            if (checkbox != null) checkbox.Checked = true;
        }
    }
}

4. 修改PageIndexChanging事件

现在调整事件逻辑,先保存再分页再保存到数据库:

protected void GridView1_PageIndexChanging(object sender, GridViewPageEventArgs e)
{
    try
    {
        // 第一步:先保存当前页的选中行
        SaveSelectedRows();
        
        // 第二步:把选中的数据存入数据库
        SaveSelectedRowsToDatabase();
        
        // 第三步:执行分页并绑定数据
        GridView1.PageIndex = e.NewPageIndex;
        BindGridView();
    }
    catch (Exception ex)
    {
        Response.Write($"操作出错:{ex.Message}");
    }
}

private void SaveSelectedRowsToDatabase()
{
    if (ViewState["SelectedRows"] == null) return;
    
    DataTable tableUserInput = (DataTable)ViewState["SelectedRows"];
    if (tableUserInput.Rows.Count == 0) return;
    
    using (SqlBulkCopy bulkCopy = new SqlBulkCopy(connString))
    {
        bulkCopy.DestinationTableName = "CustomQuizQuestions";
        try
        {
            bulkCopy.WriteToServer(tableUserInput);
            // 保存成功后可以清空ViewState,避免重复保存
            ViewState["SelectedRows"] = null;
        }
        catch (Exception ex)
        {
            Response.Write($"批量保存数据出错:{ex.Message}");
        }
    }
}

三、额外建议

  1. 避免分页时自动保存:用户可能只是切换页面查看,还没确认要保存所有选中项,建议加一个「保存选中项」的按钮,在按钮的Click事件里调用SaveSelectedRows()和SaveSelectedRowsToDatabase(),这样更符合用户操作逻辑。
  2. 消除SQL注入风险:原来的SQL语句直接拼接Request.QueryString的值,非常危险,一定要用参数化查询(上面的代码已经改了)。
  3. 错误日志代替Response.Write:正式环境里不要用Response.Write输出错误,应该用日志框架(比如NLog、Serilog)记录错误信息,避免泄露敏感信息给用户。

内容的提问来源于stack exchange,提问作者Rayomand

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.14 08:05:08