65.9K
CodeProject 正在变化。 阅读更多。
Home

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

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.89/5 (24投票s)

2011 年 3 月 20 日

CPOL

2分钟阅读

viewsIcon

228531

downloadIcon

14253

如何在 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 模型,其中包括 AlbumGenre Artist 表。我们可以看到基本的实体关系图。

AlbumViewModel 类是 AlbumGenre 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 ,其中包含标题 keywordGenre 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 网格组件。我们可以轻松使用强大的分页、筛选、排序网格功能。

参考文献

© . All rights reserved.