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

两个DataGridView间移动行后,如何保持网格滚动位置不回到顶部?

问题描述

我有两个带按钮字段的DataGridView,要实现特定角色的功能授予与撤销操作:点击「授予」按钮时,对应功能从当前DataGridView移除并显示到另一个DataGridView;撤销操作逻辑相反。目前功能正常,但每次点击按钮都会重新从数据库绑定数据,导致网格回到顶部,想保持当前滚动位置,求解决思路。

后台代码
protected void grdAllFunctions_RowCommand(object sender, GridViewCommandEventArgs e)
{
    int roleid = Convert.ToInt32(ddlUser.SelectedValue);
    int rowIndex = Convert.ToInt32(e.CommandArgument);
    GridViewRow row = grdAllFunctions.Rows[rowIndex];
    int funcid = Convert.ToInt32(row.Cells[0].Text);
    UserClass obj = new UserClass();
    try
    {
        if (ddlUser.SelectedValue == "0")
        {
            errorHandle(false, "Please Select the Role Name");
            return;
        }
        else
        {
            DataSet ds = new DataSet();
            ds.Merge(obj.checkgrantedfunctions(roleid, funcid));
            if (ds.Tables[0].Rows.Count > 0)
            {
                errorHandle(false, "This Function is Already Assigned");
                return;
            }
            else
            {
                obj.grant(roleid, funcid);
                errorHandle(true, "Successfully Granted");
                DataSet dg = new DataSet();
                dg.Merge(obj.ungrantedfunctions(roleid));
                if (dg.Tables[0].Rows.Count > 0)
                {
                    grdAllFunctions.DataSource = null;
                    grdAllFunctions.DataSource = dg.Tables[0];
                    grdAllFunctions.DataBind();
                }
                else
                {
                    grdAllFunctions.DataSource = dg.Tables[0];
                    grdAllFunctions.DataBind();
                }
                DataSet ds1 = new DataSet();
                ds1.Merge(obj.grantedfunctions(roleid));
                if (ds1.Tables[0].Rows.Count > 0)
                {
                    grdGrantedFunctions.Visible = true;
                    grdGrantedFunctions.DataSource = ds1.Tables[0];
                    grdGrantedFunctions.DataBind();
                }
                return;
            }
        }
    }
    catch (Exception ex)
    {
        Response.Write("<script>alert('" + Server.HtmlEncode(ex.Message) + "')</script>");
        return;
    }
}
解决思路

方法1:保存并恢复滚动位置

在数据绑定前用JavaScript获取GridView容器的滚动位置,存入隐藏字段;绑定完成后再读取位置并恢复。

  1. 给GridView套一个带固定高度的滚动容器:
<div id="grdContainer" style="height:400px;overflow:auto;">
    <asp:GridView ID="grdAllFunctions" runat="server" ...>
        <!-- 网格内容 -->
    </asp:GridView>
</div>
  1. 添加隐藏字段存储滚动值:
<asp:HiddenField ID="hdnScrollTop" runat="server" />
  1. 按钮点击时先执行JS保存位置:
<asp:Button ID="btnGrant" runat="server" Text="授予" CommandName="Grant" 
    OnClientClick="saveScrollPosition();" />

对应的JS函数:

function saveScrollPosition() {
    var container = document.getElementById('grdContainer');
    document.getElementById('<%= hdnScrollTop.ClientID %>').value = container.scrollTop;
}
  1. 数据绑定完成后注册脚本恢复位置:
ScriptManager.RegisterStartupScript(this, GetType(), "RestoreScroll", 
    $"document.getElementById('grdContainer').scrollTop = {hdnScrollTop.Value};", true);

方法2:避免全量数据绑定(优化方案)

直接操作GridView的行,不用重新绑定整个数据集,从根源避免滚动丢失:

  • 授予操作:从grdAllFunctions移除目标行,克隆该行并替换按钮后添加到grdGrantedFunctions
  • 撤销操作:反向执行上述逻辑
  • 同时仅更新数据库对应记录,不用拉取全量数据

示例代码(授予操作片段):

// 移除源网格的行
grdAllFunctions.Rows.RemoveAt(rowIndex);
// 克隆行并替换按钮
GridViewRow newRow = row.Clone();
for (int i = 0; i < newRow.Cells.Count; i++)
{
    newRow.Cells[i].Text = row.Cells[i].Text;
    if (i == newRow.Cells.Count - 1)
    {
        Button btnRevoke = new Button();
        btnRevoke.Text = "撤销";
        btnRevoke.CommandName = "Revoke";
        btnRevoke.CommandArgument = grdGrantedFunctions.Rows.Count.ToString();
        newRow.Cells[i].Controls.Add(btnRevoke);
    }
}
grdGrantedFunctions.Rows.Add(newRow);
grdGrantedFunctions.Visible = true;

方法3:使用UpdatePanel局部刷新

把两个GridView放到UpdatePanel中,只刷新网格区域,页面整体不会回滚:

<asp:UpdatePanel ID="UpdatePanel1" runat="server">
    <ContentTemplate>
        <asp:GridView ID="grdAllFunctions" runat="server" ...></asp:GridView>
        <asp:GridView ID="grdGrantedFunctions" runat="server" ...></asp:GridView>
    </ContentTemplate>
    <Triggers>
        <asp:AsyncPostBackTrigger ControlID="grdAllFunctions" EventName="RowCommand" />
        <asp:AsyncPostBackTrigger ControlID="grdGrantedFunctions" EventName="RowCommand" />
    </Triggers>
</asp:UpdatePanel>

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.21 14:45:37