MvcContrib Grid 在 ASP.NET MVC3 中的分页和搜索






4.89/5 (24投票s)
如何在 ASP.NET MVC3 中实现 MvcContrib Grid 的分页、排序、筛选和保留查询 URL
引言
本文向您展示如何在 ASP.NET MVC3 中实现 MvcContrib
Grid 的分页、筛选和保留搜索 URL。
背景
MvcContrib
Grid 提供带有列排序的漂亮分页界面。在实际应用中,我们需要聚合复杂的 ViewModel
来呈现网格视图。我们还应该为网格视图提供多个搜索过滤器和关键词。
因此,我实现了干净的 PagedViewModel<T>
类,以便在 ASP.NET MVC3 中简化 MvcContrib
Grid 的分页和筛选,基于 这篇文章。
Using the Code
摘要
我向原始源代码添加了一些代码和类,以简化实现,如下所示
PagedViewModel<T>
包含IPagenation<T>
、AddFilter
方法以及排序/分页信息- 在列表页和视图页之间保留查询 URL
业务层
让我们使用 http://chinookdatabase.codeplex.com/ 的音乐商店数据库作为我们的 AlbumServie。(*我将 mdf 附加在我们的 MVC 项目的 *web.config* 中,并带有基本的连接字符串。)
让我们添加 MVCMusicStoreDB
EF4 模型,其中包括 Album
、Genre
和 Artist
表。我们可以看到基本的实体关系图。
AlbumViewModel
类是 Album
、Genre
和 Artist
实体的复合 ViewModel
类。 MvcContrib
Grid 在 AutoGenerateColumns()
函数中使用这些 Display*
和 ScaffoldColumn
属性。
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
namespace MvcMusicStore.Models
{
public class AlbumViewModel
{
[DisplayName("ID")]
public int AlbumId { get; set; }
[ScaffoldColumn(false)]
public int? GenreId { get; set; }
[DisplayName("Genre")]
public string Genre { get; set; }
[ScaffoldColumn(false)]
public int? ArtistId { get; set; }
[DisplayName("Artist")]
public string Artist { get; set; }
[ScaffoldColumn(false)]
public string AlbumTitle { get; set; }
[DisplayName("Price")]
[DisplayFormat(DataFormatString = "{0:c}")]
public decimal AlbumPrice { get; set; }
}
}
让我们构建我们的主要业务服务方法。第一步是在 AlbumService
中添加一些基本的读取方法。为了简单快速的实现,我们没有实现 CUD 方法和任何 UoW 或 Repository 层。
namespace MvcMusicStore.Models
{
public class AlbumService
{
private MvcMusicStoreEntities _context;
public AlbumService()
{
_context = new MvcMusicStoreEntities();
}
public IQueryable<AlbumViewModel> GetAlbumsView()
{
var query = from a in GetAlbums()
select new AlbumViewModel
{
AlbumId = a.AlbumId,
GenreId = a.GenreId,
Genre = a.Genre.Name,
ArtistId = a.ArtistId,
Artist = a.Artist.Name,
AlbumTitle = a.Title,
AlbumPrice = a.Price
};
return query;
}
public AlbumViewModel FindAlbumView(int albumId)
{
return GetAlbumsView().Where(a => a.AlbumId == albumId).Single();
}
public IQueryable<Album> GetAlbums()
{
return _context.Albums;
}
public IQueryable<Genre> GetGenres()
{
return _context.Genres;
}
public IQueryable<Artist> GetArtists()
{
return _context.Artists;
}
public void Save()
{
_context.SaveChanges();
}
}
}
PagedViewModel<T>
PagedViewModel<T>
是一个泛型容器,用于保存所有网格呈现的数据,包括搜索过滤器。还有几个 AddFilter
实现,用于注册简单的过滤器,如搜索关键字,而 SelectListFilterViewItem
用于保存 SelectList
对象,并添加 viewdata 字典。
为了支持对 PagedViewModel<T>
的流畅过滤器设置功能,我们应该实现 AddFilter
和 Setup
方法。
namespace MvcMusicStore.Models
{
public class PagedViewModel<T>
{ ...
public PagedViewModel<T> AddFilter(Expression<Func<T, bool>> predicate)
{
Query = Query.Where(predicate);
return this;
}
public PagedViewModel<T> AddFilter<TValue>
(string key, TValue value, Expression<Func<T, bool>> predicate)
{
ProcessQuery(value, predicate);
ViewData[key] = value;
return this;
}
public PagedViewModel<T> AddFilter<TValue>
(string keyField, object value, Expression<Func<T, bool>> predicate,
IQueryable<TValue> query, string textField)
{
ProcessQuery(value, predicate);
var selectList = query.ToSelectList(keyField, textField, value);
ViewData[keyField] = selectList;
return this;
}
public PagedViewModel<T> Setup()
{
if (string.IsNullOrWhiteSpace(GridSortOptions.Column))
{
GridSortOptions.Column = DefaultSortColumn;
}
PagedList = Query.OrderBy
(GridSortOptions.Column, GridSortOptions.Direction)
.AsPagination(Page ?? 1, PageSize ?? 10);
return this;
}
private void ProcessQuery<TValue>
(TValue value, Expression<Func<T, bool>> predicate)
{
if (value == null) return;
if (typeof(TValue) == typeof(string))
{
if (string.IsNullOrWhiteSpace(value as string)) return;
}
Query = Query.Where(predicate);
}
}
}
控制器中的列表操作方法
让我们在 AlbumController
中制作一个 AlbumController
的列表方法,其中包含搜索过滤器、排序和分页。我们可以将流畅的查询过滤器添加到 PagedViewModel
的过滤器管道中。
namespace MvcMusicStore.Controllers
{
public class AlbumController : Controller
{
private AlbumService _service;
public AlbumController()
{
_service = new AlbumService();
}
public ActionResult Index(string albumTitle,
int? genreId, int? artistId, GridSortOptions gridSortOptions, int? page)
{
var pagedViewModel = new PagedViewModel<AlbumViewModel>
{
ViewData = ViewData,
Query = _service.GetAlbumsView(),
GridSortOptions = gridSortOptions,
DefaultSortColumn = "AlbumId",
Page = page,
}
.AddFilter("albumTitle", albumTitle,
a => a.AlbumTitle.Contains(albumTitle))
.AddFilter("genreId", genreId,
a => a.GenreId == genreId, _service.GetGenres(), "Name")
.AddFilter("artistId", artistId,
a => a.ArtistId == artistId, _service.GetArtists(), "Name")
.Setup();
return View(pagedViewModel);
}
...
}
}
MvcContrib Grid 的列表 Razor 视图页面
让我们制作列表视图页面。我们可以轻松地填充两个下拉列表,而无需 PagedViewModel<T>
中的任何额外代码。此外,我们使用 Html.ActionQueryLink
辅助方法添加一个链接来保留查询 string
,例如 "/Album/Details/420?albumTitle=Ro&genreId=1
"。
@using MvcMusicStore.Common
@using MvcMusicStore.Models;
@using MvcContrib.UI.Grid;
@model PagedViewModel<AlbumViewModel>
@{
ViewBag.Title = "Album List";
}
<h2>Album List</h2>
@using (Html.BeginForm("Index", "Album",
FormMethod.Get, new { id = "albumSearch" }))
{
<label>
Title @Html.TextBox("albumTitle")
Genre @Html.DropDownList("genreId", "-- Select All --")
</label>
<label>
Artist @Html.DropDownList("artistId", "-- Select All --")
<input class="button" value="Search" type="submit" />
</label>
}
@{Html.RenderPartial("Pager", Model.PagedList);}
@Html.Grid(Model.PagedList).AutoGenerateColumns().Columns(
column =) {column.For(x =) Html.ActionQueryLink(x.AlbumTitle, "Details",
new { id = x.AlbumId })).Named("AlbumTitle").InsertAt(2);
}).Sort(Model.GridSortOptions).Attributes(@class =) "grid-style")
让我们看看 SearchBox
,其中包含标题 keyword
、Genre
和 Album
下拉列表。Contrib Grid 提供列筛选和分页 UI。

我们可以从详细信息页面返回到列表页面,并保留查询选项。让我们添加一个代码片段,通过使用添加的 ToRouteDic
扩展方法将路由 URL 保存到 ViewBag
。
namespace MvcMusicStore.Controllers
{
public class AlbumController : Controller
{ ...
public ActionResult Details(int id)
{
var viewModel = _service.FindAlbumView(id);
ViewBag.RouteDicForList = Request.QueryString.ToRouteDic();
return View(viewModel);
}
}
}
让我们还原 ViewBag
数据以在 Details
视图页面中还原查询 URL。
@model MvcMusicStore.Models.AlbumViewModel
@{
ViewBag.Title = "Details";
}
<h2>Album Details - @Model.AlbumTitle</h2>
<p>
@Html.ActionLink("Back to List", "Index",
ViewBag.RouteDicForList as RouteValueDictionary)
</p>
结论
MvcContrib
Grid 是 MVC3 框架的一个不错的 web 网格组件。我们可以轻松使用强大的分页、筛选、排序网格功能。
参考文献
- Raj Kaimal: ASP.NET MVC 使用 MVCContrib Grid 和 Pager 进行分页/排序/筛选
- MVC Contrib 主页
- Chinook 示例数据库
- CSS 和设计:Styleshout.com