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

ASP.NET GridView拖拽排序后无法同步前端变更至后端的问题求助

问题描述

我有一个绑定服务器端Categories表的GridView,前端配备了拖拽(drag and drop)脚本用于调整分类的顺序,同时需要更新其Order字段中的排序位置。但目前,在拖拽调整行顺序后点击Update Order按钮时,后端获取到的仍是绑定到GridView的初始对象,而非变更后的行。我希望将前端的变更传递到服务器端,但系统始终仅发送初始绑定的数据,恳请提供帮助。

页面标记(Markup)
<asp:GridView ID="gvData" runat="server" AutoGenerateColumns="False" CssClass="table table-striped grab"
    EnableViewState="True" GridLines="None" OnRowDataBound="gvData_RowDataBound"
    EmptyDataText="No Data Found" EmptyDataRowStyle-CssClass="emptyDataMessage"
    AllowSorting="True" DataKeyNames="ExternalId">
    <Columns>
        <asp:TemplateField HeaderText="#" ItemStyle-Width="1%" HeaderStyle-HorizontalAlign="Center"
            ItemStyle-HorizontalAlign="Center">
            <ItemTemplate>                
            <asp:Label ID="lbCategoryId" runat="server" CssClass="sortable-field" text='<%# Container.DataItemIndex + 1 %>'/>
            </ItemTemplate>
        </asp:TemplateField>
        <asp:TemplateField HeaderText="Name" HeaderStyle-HorizontalAlign="Left" ItemStyle-HorizontalAlign="Left">
            <ItemTemplate>
                <asp:HyperLink ID="hlCategoryDetail" runat="server" />
            </ItemTemplate>
        </asp:TemplateField>
        <asp:TemplateField HeaderText="Nick" HeaderStyle-HorizontalAlign="Left" ItemStyle-HorizontalAlign="Left">
            <ItemTemplate>
                <asp:Literal ID="ltNick" runat="server" />               
            </ItemTemplate>
        </asp:TemplateField>
        <asp:TemplateField HeaderText="Order" ItemStyle-Width="1%" HeaderStyle-HorizontalAlign="Left" ItemStyle-HorizontalAlign="Left">
            <ItemTemplate>
                <asp:HiddenField ID="hfOriginalIndex" runat="server" Value="<%# Container.DataItemIndex %>" />
                <asp:Label ID="lbSort" runat="server" CssClass="sortable-field" text='<%# Container.DataItemIndex + 1 %>'/>
            </ItemTemplate>
        </asp:TemplateField>
        <asp:TemplateField HeaderText="-" HeaderStyle-HorizontalAlign="Center" ItemStyle-HorizontalAlign="Center">
            <ItemTemplate>
                <asp:Label ID="lbAlert" runat="server" CssClass="text-danger" />
            </ItemTemplate>
        </asp:TemplateField>
    </Columns>
    <EmptyDataRowStyle CssClass="emptyDataMessage" />
</asp:GridView>
<div class="col-sm-4 col-sm-offset-10">
    <asp:Button ID="btnUpdateOrder" CssClass="btn btn-primary" Text="Update Order" runat="server" OnClick="UpdateOrder" />
</div>
后端代码(Code Behind)
protected void gvData_RowDataBound(object sender, GridViewRowEventArgs e)
{
    if (e.Row.DataItem != null)
    {
        var category = (PaymentCategory)e.Row.DataItem;
        var hlCategoryDetail = (HyperLink)e.Row.FindControl("hlCategoryDetail");
        var ltNick = (Literal)e.Row.FindControl("ltAlias");
        var lbOrder = (Label)e.Row.FindControl("lbSort");
        var lbAlert = (Label)e.Row.FindControl("lbAlert");
        var lbCategoryId = (Label)e.Row.FindControl("lbCategoryId");                

        lbCategoryId.Text = category.Id.ToString();
        hlCategoryDetail.Text = category.Name;
        hlCategoryDetail.NavigateUrl = "~/Default.aspx?action=EditPaymentCategory&id=" + category.Id;                
    }
}

protected void UpdateSort(object sender, EventArgs e)
{
    int[] sortIds = (from p in Request.Form["lbSort"].Split(',') select int.Parse(p)).ToArray();
    foreach (GridViewRow row in gvData.Rows)
    {
        //Access Cell values.
        //int categoryId = int.Parse(((Label)row.FindControl("lbCategoryId")).Text);
        var ltNick = (Literal)row.FindControl("ltNick");
        int origIndex = int.Parse(((HiddenField)row.FindControl("hfOriginalIndex")).Value);
        int orderId = int.Parse(((Label)row.FindControl("lbOrder")).Text);
        string categoryId = gvData.DataKeys[origIndex].Value.ToString();
        
        //Controller.UpdateCategorySortOrder(category, orderId);
    }
    Response.Redirect(Request.Url.AbsoluteUri);
}
拖拽脚本(Drag and Drop Script)
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js"></script>
<link rel="stylesheet" href="https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.24/themes/smoothness/jquery-ui.css" />
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.24/jquery-ui.min.js"></script>
<script src="jquery.tablednd.js" type="text/javascript"></script>
<script type="text/javascript">
    $(function () {
        $("[id*=gvData]").sortable({
            items: 'tr:not(tr:first-child)',
            cursor: 'pointer',
            axis: 'y',
            dropOnEmpty: false,
            start: function (e, ui) {
                ui.item.addClass("selected");
            },
            stop: function (e, ui) {
                ui.item.removeClass("selected");
                //iterate through rows and update Sort field
                $("[id*=lbCategoryId]").each(function (index) {
                    $(this).text(index + 1);
                });
                $("[id*=gvData] tbody tr").each(function (index) {
                    $(this).find("[id*=hfOriginalIndex]").val(index);                    
                    // Update categoryId using data attribute
                    var categoryId = $(this).find("[id*=lbCategoryId]").data("Id").val(categoryId);                   
                });               
            },            
            receive: function (e, ui) {
                $(this).find("tbody").append(ui.item);
            }
        });
    });    
</script>
解决方案

问题核心:ASP.NET中Label控件的内容不会随表单回发,只有输入类控件(如HiddenField、TextBox)的值会被提交到服务器。你当前用Label存储排序号和分类ID,拖拽修改后这些值无法传递到后端。

修复步骤

  1. 替换Label为HiddenField存储关键数据
    保留Label用于前端显示,新增HiddenField存储需要回发的分类ID和当前排序值:

    <!-- 分类ID列修改 -->
    <asp:TemplateField HeaderText="#" ItemStyle-Width="1%" HeaderStyle-HorizontalAlign="Center"
        ItemStyle-HorizontalAlign="Center">
        <ItemTemplate>                
            <asp:HiddenField ID="hfCategoryId" runat="server" Value='<%# Eval("Id") %>' />
            <asp:Label ID="lbCategoryId" runat="server" CssClass="sortable-field" text='<%# Container.DataItemIndex + 1 %>'/>
        </ItemTemplate>
    </asp:TemplateField>
    
    <!-- 排序列修改 -->
    <asp:TemplateField HeaderText="Order" ItemStyle-Width="1%" HeaderStyle-HorizontalAlign="Left" ItemStyle-HorizontalAlign="Left">
        <ItemTemplate>
            <asp:HiddenField ID="hfOriginalIndex" runat="server" Value="<%# Container.DataItemIndex %>" />
            <asp:HiddenField ID="hfCurrentSort" runat="server" Value="<%# Container.DataItemIndex + 1 %>" />
            <asp:Label ID="lbSort" runat="server" CssClass="sortable-field" text='<%# Container.DataItemIndex + 1 %>'/>
        </ItemTemplate>
    </asp:TemplateField>
    
  2. 修改前端脚本,更新HiddenField的值
    拖拽停止后,同步更新显示用Label和回发用HiddenField的内容:

    stop: function (e, ui) {
        ui.item.removeClass("selected");
        $("[id*=gvData] tbody tr").each(function (index) {
            // 更新前端显示的序号
            $(this).find("[id*=lbCategoryId]").text(index + 1);
            $(this).find("[id*=lbSort]").text(index + 1);
            // 更新回发用的排序值
            $(this).find("[id*=hfCurrentSort]").val(index + 1);
            // 更新原索引(如果需要)
            $(this).find("[id*=hfOriginalIndex]").val(index);
        });               
    },
    
  3. 后端调整数据读取逻辑
    从HiddenField中获取更新后的分类ID和排序值,不再依赖Label或原DataKeys索引:

    protected void UpdateSort(object sender, EventArgs e)
    {
        List<(int CategoryId, int NewOrder)> sortList = new List<(int, int)>();
        foreach (GridViewRow row in gvData.Rows)
        {
            int categoryId = int.Parse(((HiddenField)row.FindControl("hfCategoryId")).Value);
            int newOrder = int.Parse(((HiddenField)row.FindControl("hfCurrentSort")).Value);
            sortList.Add((categoryId, newOrder));
        }
        // 调用业务逻辑更新排序
        // Controller.UpdateCategorySortOrders(sortList);
        Response.Redirect(Request.Url.AbsoluteUri);
    }
    

额外优化

  • 移除无用的jquery.tablednd.js,当前已使用jQuery UI的sortable功能;
  • 将GridView的DataKeyNames设置为分类主键Id,方便后续直接通过DataKeys获取主键(可选);
  • 拖拽脚本中删除无效的data("Id")赋值代码,直接操作HiddenField即可。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.30 17:57:32