ASP.NET Web Forms 4.5中基于TemplateField的GridView排序问题
嘿,我之前刚好踩过GridView结合RowDataBound排序的坑,结合你给出的代码结构,给你整理几个能快速解决的步骤:
1. 先给GridView启用排序相关属性
首先得在你的ASPX代码里给GridView加上排序开关和事件绑定,不然默认是不支持排序的:
<asp:GridView runat="server" ID="testGrid" selectMethod="testGrid_GetData" AutoGenerateColumns="false" AutoGenerateDeleteButton="true" OnRowDataBound="testGrid_RowDataBound" ItemType="testItem" DeleteMethod="testGrid_DeleteItem" AutoGenerateEditButton="true" UpdateMethod="testGrid_UpdateItem" AllowSorting="true" <!-- 开启排序支持 --> OnSorting="testGrid_Sorting" <!-- 绑定排序事件(自定义排序时需要) --> SortExpression="Id" <!-- 设置默认排序字段,比如主键Id --> >
2. 修改数据源方法,支持排序参数
你的testGrid_GetData方法需要接收排序相关的参数,然后在数据源层面做排序(这很重要,因为RowDataBound是在数据绑定后才执行的,不能靠它来排序)。如果用的是IQueryable(比如EF的DbSet),可以直接用LINQ处理:
public IQueryable<testItem> testGrid_GetData(string sortExpression = "Id", SortDirection sortDirection = SortDirection.Ascending) { using(var dbContext = new YourDbContext()) { var query = dbContext.testItems.AsQueryable(); // 根据传入的排序字段和方向处理 switch(sortExpression) { case "Name": // 字段名要和GridView的SortExpression对应 query = sortDirection == SortDirection.Ascending ? query.OrderBy(x => x.Name) : query.OrderByDescending(x => x.Name); break; case "CreateDate": query = sortDirection == SortDirection.Ascending ? query.OrderBy(x => x.CreateDate) : query.OrderByDescending(x => x.CreateDate); break; // 其他需要排序的字段都在这里加case default: query = sortDirection == SortDirection.Ascending ? query.OrderBy(x => x.Id) : query.OrderByDescending(x => x.Id); break; } return query; } }
3. 确保RowDataBound不干扰排序
你之前用RowDataBound从其他表取数据的逻辑完全没问题,但要注意绝对不要在这个事件里修改行的顺序(比如手动移动行、重新绑定数据),因为数据源已经排好序了,RowDataBound只负责给当前行补充关联数据就行:
protected void testGrid_RowDataBound(object sender, GridViewRowEventArgs e) { if (e.Row.RowType == DataControlRowType.DataRow) { // 获取当前行绑定的实体 testItem currentItem = (testItem)e.Row.DataItem; // 从其他表取关联数据,比如分类名称 using(var dbContext = new YourDbContext()) { var relatedData = dbContext.OtherTables.FirstOrDefault(t => t.Id == currentItem.RelatedId); if(relatedData != null) { // 把数据绑定到TemplateField里的控件 Label lblRelated = (Label)e.Row.FindControl("lblRelatedData"); if(lblRelated != null) { lblRelated.Text = relatedData.DisplayName; } } } } }
4. 给TemplateField添加排序触发(如果需要)
如果你的TemplateField需要支持点击表头排序,得在HeaderTemplate里加一个LinkButton,指定CommandName为Sort,CommandArgument为对应的排序字段:
<asp:TemplateField SortExpression="DisplayName"> <!-- SortExpression要和数据源方法里的字段对应 --> <ItemTemplate> <asp:Label runat="server" ID="lblRelatedData" Text='<%# Eval("DisplayName") %>'></asp:Label> </ItemTemplate> <HeaderTemplate> <asp:LinkButton runat="server" CommandName="Sort" CommandArgument="DisplayName"> 关联数据名称 <%-- 可选:显示排序箭头,直观展示当前排序方向 --%> <asp:Image runat="server" ID="imgSortArrow" Visible='<%# testGrid.SortExpression == "DisplayName" %>' ImageUrl='<%# testGrid.SortDirection == SortDirection.Ascending ? "~/Images/up-arrow.png" : "~/Images/down-arrow.png" %>' /> </asp:LinkButton> </HeaderTemplate> </asp:TemplateField>
几个关键注意点
- 排序必须在数据源层面做:不要试图在RowDataBound里排序,因为这时候数据已经绑定到GridView了,修改只会打乱顺序
- SortExpression要统一:GridView的SortExpression、数据源方法里的case字段、TemplateField的SortExpression必须完全一致,否则排序不生效
- 如果用的是List而不是IQueryable,把数据源方法里的IQueryable改成List,然后用LINQ的OrderBy/OrderByDescending处理就行
内容的提问来源于stack exchange,提问作者Jinmo Chong
相关产品推荐
相关产品推荐

