【译】MVC3 20个秘方-(8)为列表结果分页
问题
你有一个很庞大列表形式的结果,它加载的时间很长。或者你在这个很长的列表中不能很轻松的找到你的结果。把结果划分成多个页面将会减少页面载入的时间并且帮你更快的找到你想要的结果,特别是结果已经被排序的情况下。
解决方案
使用PagedList.MVC穿梭于各个记录列表页。
讨论
为一个应用程序分页你需要通过NuGet Library安装一个新的DLL“pagedList.MVC”。这将生成一个比完整的列表更好的分页列表。选择工具->Library Package Manager->Add Library Package Reference.在左边选择online 按钮。在搜索框里输入pagedList然后按下图安装PagedList.MVC:
一旦pagedlist安装完成,创建分页的代码将被添加成为一个partial view。这允许以后为结果分页时可以重用这个partial view。由于分页的过程并没有真正包含许多动态变量,所以这是一个完美的机会去重用这个HTML在每一个结果列表页而带来甚微的影响,同时保持外观一致。
作为开始,展开Views 文件夹。右击 Shared文件,选择->添加->View。命名为_Paging,确定选着“Create as partial view”点击添加。在新创建的view中添加如下代码:
<p>
@if (Model.HasPreviousPage)
{
@Html.ActionLink("<< First", "Index", new
{
page = 1,
sortOrder = ViewBag.CurrentSortOrder
})
@Html.Raw(" ");
@Html.ActionLink("< Prev", "Index", new
{
page = Model.PageNumber - 1,
sortOrder =
ViewBag.CurrentSortOrder
})
}
else
{
@:<< First
@Html.Raw(" ");
@:< Prev
}
@if (Model.HasNextPage)
{
@Html.ActionLink("Next >", "Index", new
{
page = Model.PageNumber + 1,
sortOrder = ViewBag.CurrentSortOrder
})
@Html.Raw(" ");
@Html.ActionLink("Last >>", "Index", new
{
page = Model.PageCount,
sortOrder = ViewBag.CurrentSortOrder
})
}
else
{
@:Next >
@Html.Raw(" ")
@:Last >>
}
</p>
这个View 创建了4个link。首页,前一页,下一页和末页。我说有4个link是因为如果前边没有可用的页面。那么前一页和首页的链接就是不可用的。每个link传递2个变量到Index()action。页码和当前排序的规则列。当前排序的规则列可以确保我分页之后用户也不会丢失他选择的排序规则。
接下来,我们要在Book/Index 这个view上做一些更改:
@model PagedList.IPagedList<MvcApplication4.Models.Book>
<h2>@ViewBag.Title</h2>
<p>
@Html.ActionLink((string)ViewBag.CreateLink, "Create")
</p>
@Html.Partial("_Paging")
<table>
<tr>
<th>
@Html.ActionLink((string)ViewBag.TitleDisplay,
"Index", new { sortOrder = ViewBag.TitleSortParam })
</th>
<th>
@Html.ActionLink((string)ViewBag.IsbnDisplay,
"Index", new { sortOrder = ViewBag.IsbnSortParam })
</th>
<th>
@ViewBag.SummaryDisplay
</th>
<th>
@Html.ActionLink((string)ViewBag.AuthorDisplay,
"Index", new
{
sortOrder =
ViewBag.AuthorSortParam
})
</th>
<th>
@ViewBag.ThumbnailDisplay
</th>
<th>
@Html.ActionLink((string)ViewBag.PriceDisplay,
"Index", new { sortOrder = ViewBag.PriceSortParam })
</th>
<th>
@Html.ActionLink((string)ViewBag.PublishedDisplay,
"Index", new
{
sortOrder =
ViewBag.PublishedSortParam
})
</th>
<th>
</th>
</tr>
@foreach (var item in Model)
{
<tr>
<td>
@Html.DisplayFor(modelItem => item.Title)
</td>
<td>
@Html.DisplayFor(modelItem => item.Isbn)
</td>
<td>
@Html.DisplayFor(modelItem => item.Summary)
</td>
<td>
@Html.DisplayFor(modelItem => item.Author)
</td>
<td>
@Html.DisplayFor(modelItem => item.Thumbnail)
</td>
<td>
@Html.DisplayFor(modelItem => item.Price)
</td>
<td>
@Html.DisplayFor(modelItem => item.Published)
</td>
<td>
@Html.ActionLink((string)ViewBag.EditLink,
"Edit", new { id = item.ID }) |
@Html.ActionLink((string)ViewBag.DetailsLink,
"Details", new { id = item.ID }) |
@Html.ActionLink((string)ViewBag.DeleteLink,
"Delete", new { id = item.ID })
</td>
</tr>
}
</table>
@Html.Partial("_Paging")
上边的例子包含了对View的3个改变。第一,更新了model的type成强类型PagedList.IPagedList。
第二,_Paging partial view被引用了2次。一次在table上。一次在table下。这样可以方便用户点击。
最后,要更新BookController。Index()这个 action 要被更新去接收一个新的参数:page。并且用一个 paged List 去替换原来的返回值 list。并且,在sort order 块中。添加一个新的 ViewBag变量 设置当前的sort order。代码如下:
(译者:我修改了原书中的代码,因为这段代码中有bug。ToChangedList接收的第一个参数不能为0,但是默认action传入的page是1.这样会引发异常):
using System;
using System.Collections.Generic;
using System.Data;
using System.Data.Entity;
using System.Linq;
using System.Linq.Dynamic;
using System.Web;
using System.Web.Mvc;
using MvcApplication.Models;
using MvcApplication.Utils;
using PagedList;
namespace MvcApplication.Controllers
{
public class BooksController : Controller
{
private BookDBContext db = new BookDBContext();
//
// GET: /Books/
public ViewResult Index(string sortOrder, int page = 1)
{
#region ViewBag Sort Params
ViewBag.CurrentSortOrder = sortOrder;
#endregion
const int maxRecords = 2;// maxRecords 是每页的最大记录数
var books = db.Books.OrderBy(sortOrder);
var currentPage = page <= 0 ? 1 : page;
return View(books.ToPagedList(currentPage,
maxRecords));
}
}
}
如果你想进一步扩展局部视图(_Paging)重用在其他列表的结果,你只需要确保为每个列表设置相同的ViewBag。在这种情况下,列表结果
不在像这样Index() action中。你可以更新Html.ActionLink调用另一个ViewBag变量定义的动作,使得它可能动态的使用。
另请参见