MVC Razor WebGrid表头排序丢失类别筛选状态的解决问询
解决MVC Razor WebGrid排序丢失筛选状态的问题
问题根源
WebGrid默认生成的表头排序链接仅携带sort(排序字段)和sortdir(排序方向)参数,不会自动附加当前的筛选条件(比如类别ID)。点击排序时控制器无法获取之前的筛选参数,因此返回全部数据,导致筛选状态丢失。
核心解决方案
让WebGrid的排序链接自动带上当前的筛选参数,同时控制器方法支持接收筛选+排序参数,组合执行数据查询。以下是完整实现代码:
1. 模型定义
// 产品实体模型 public class Product { public int Id { get; set; } public string Name { get; set; } public decimal Price { get; set; } public int CategoryId { get; set; } public string CategoryName { get; set; } } // 筛选+列表视图模型 public class ProductFilterViewModel { public int? SelectedCategoryId { get; set; } public List<SelectListItem> Categories { get; set; } public WebGrid Grid { get; set; } public IEnumerable<Product> Products { get; set; } }
2. 控制器实现
public ActionResult Index(int? selectedCategoryId, string sortColumn = "Name", string sortDirection = "ASC") { // 构造类别下拉选项(实际项目从数据库读取) var categories = new List<SelectListItem> { new SelectListItem { Value = "", Text = "全部类别" }, new SelectListItem { Value = "1", Text = "电子产品" }, new SelectListItem { Value = "2", Text = "家居用品" }, new SelectListItem { Value = "3", Text = "服装" } }; // 获取模拟产品数据(实际从数据库查询) var products = GetMockProducts(); // 应用类别筛选 if (selectedCategoryId.HasValue) { products = products.Where(p => p.CategoryId == selectedCategoryId.Value); } // 应用排序逻辑 var property = typeof(Product).GetProperty(sortColumn); products = sortDirection.Equals("ASC", StringComparison.OrdinalIgnoreCase) ? products.OrderBy(p => property.GetValue(p, null)) : products.OrderByDescending(p => property.GetValue(p, null)); // 初始化WebGrid,指定排序参数 var grid = new WebGrid( source: products, defaultSort: sortColumn, sortDirectionFieldName: "sortDirection", canSort: true ); // 构建视图模型 var viewModel = new ProductFilterViewModel { SelectedCategoryId = selectedCategoryId, Categories = categories, Grid = grid, Products = products }; return View(viewModel); } // 模拟数据库产品数据 private List<Product> GetMockProducts() { return new List<Product> { new Product { Id = 1, Name = "手机", Price = 2999, CategoryId = 1, CategoryName = "电子产品" }, new Product { Id = 2, Name = "电视", Price = 5999, CategoryId = 1, CategoryName = "电子产品" }, new Product { Id = 3, Name = "沙发", Price = 3999, CategoryId = 2, CategoryName = "家居用品" }, new Product { Id = 4, Name = "床单", Price = 299, CategoryId = 2, CategoryName = "家居用品" }, new Product { Id = 5, Name = "T恤", Price = 99, CategoryId = 3, CategoryName = "服装" }, new Product { Id = 6, Name = "牛仔裤", Price = 199, CategoryId = 3, CategoryName = "服装" } }; }
3. Razor页面(Index.cshtml)
关键是修改WebGrid生成的排序链接,追加当前筛选参数:
@model ProductFilterViewModel @{ ViewBag.Title = "产品列表"; var selectedCategoryId = Model.SelectedCategoryId ?? 0; } <h2>产品列表</h2> <!-- 类别筛选区域 --> <div class="filter-area mb-3"> <label class="me-2">选择类别:</label> @Html.DropDownListFor(m => m.SelectedCategoryId, Model.Categories, new { @id = "categoryFilter", @class = "form-control d-inline-block w-auto" }) <button id="filterBtn" class="btn btn-primary ms-2">筛选</button> </div> <!-- WebGrid容器 --> <div id="grid-container" class="grid-container"> @{ var grid = Model.Grid; grid.Columns( grid.Column("Id", "ID", canSort: true), grid.Column("Name", "产品名称", canSort: true), grid.Column("Price", "价格", canSort: true), grid.Column("CategoryName", "类别") ); // 生成WebGrid原始HTML string gridHtml = grid.GetHtml( tableStyle: "table table-striped table-bordered", headerStyle: "table-dark", sortColumnHeaderStyle: "sortable-column", sortDirectionHeaderStyle: "sort-direction", mode: WebGridPagerModes.All, columns: grid.Columns ).ToString(); // 给排序链接追加类别筛选参数 if (selectedCategoryId > 0) { gridHtml = gridHtml.Replace("?", $"?selectedCategoryId={selectedCategoryId}&"); gridHtml = gridHtml.Replace("&sort=", $"&selectedCategoryId={selectedCategoryId}&sort="); } // 输出修改后的WebGrid @Html.Raw(gridHtml) } </div> <!-- 筛选交互脚本 --> <script src="~/Scripts/jquery-3.6.0.min.js"></script> <script> $(document).ready(function () { // 筛选按钮点击事件 $("#filterBtn").click(function () { var categoryId = $("#categoryFilter").val(); window.location.href = '@Url.Action("Index")' + (categoryId ? `?selectedCategoryId=${categoryId}` : ""); }); // 下拉框回车触发筛选 $("#categoryFilter").keypress(function (e) { if (e.which === 13) $("#filterBtn").click(); }); }); </script>
4. 优化方案:AJAX无刷新排序(可选)
如果想要更流畅的体验,可改用WebGrid的AJAX模式,避免页面刷新:
- 修改WebGrid初始化代码,添加AJAX配置:
var grid = new WebGrid( source: products, defaultSort: sortColumn, sortDirectionFieldName: "sortDirection", canSort: true, ajaxUpdateContainerId: "grid-container" // 指定AJAX更新的容器ID );
- 替换页面脚本,拦截排序链接的点击事件,追加筛选参数后发起AJAX请求:
$(document).ready(function () { // 筛选按钮逻辑不变 $("#filterBtn").click(function () { var categoryId = $("#categoryFilter").val(); $("#grid-container").load('@Url.Action("Index")' + (categoryId ? `?selectedCategoryId=${categoryId}` : "")); }); // 拦截排序链接点击,追加筛选参数 $(document).on("click", ".sortable-column a", function (e) { e.preventDefault(); var url = $(this).attr("href"); var categoryId = $("#categoryFilter").val(); if (categoryId) { url += (url.indexOf("?") > -1 ? "&" : "?") + `selectedCategoryId=${categoryId}`; } $("#grid-container").load(url); }); });
问题场景说明
- 问题状态:选择“电子产品”筛选后,点击“价格”表头排序,页面跳转到全部产品的排序结果,丢失筛选状态。
- 修复后状态:筛选后表头排序链接自动携带
selectedCategoryId=1参数,点击排序时仅对当前类别下的产品进行排序,维持筛选状态。
内容的提问来源于stack exchange,提问作者Chris Singleton
相关产品推荐
相关产品推荐

