再谈使用X.PagedList.Mvc 分页(ASP.NET Core 2.1)
在以前的博文中写过使用X.PagedList.Mvc组件来对ASP.NET MVC应用程序进行分页,可以参考此篇随笔:Asp.net MVC 使用PagedList(新的已更名 为X.PagedList.Mvc) 分页
但是旧有的X.PagedList.MVC 依赖于.NET Framework版本,为了能够支持ASP.NET Core MVC跨平台的实现,在ASP.NET Core MVC中无需再安装.NET Framework,只需依赖于.NET Core。而且所有ASP.NET Core MVC的控制器 操作方法都默认是 异步方法,GitHub网址是:https://github.com/dncuug/X.PagedList
自己写一个分页并不麻烦,但功能肯定没有 X.PagedList.Mvc.Core 强大。本文简要介绍一下 X.PagedList.Mvc.Core 用于ASP.NET Core MVC的情况。
第一步:安装 X.PagedList.Mvc.Core包,会自动安装PagedList。有三种方式都可以完成安装。
第1种、通过NuGet包获取。在Visual Stuio 2017中,工具 --- NuGet包管理器 --- 管理解决方案中的NuGet程序包 ---浏览选项卡-- 在下面的搜索文本框中输入 X.PagedList,或直接搜索 X.PagedList.Mvc.Core
第2种:在NuGet程序包管理控制台安装 ,输入Install-package X.PagedList.Mvc.Core,自动安装最新的版本的程序包和依赖(目前 为7.5.0),在解决方案管理器 中的依赖项,可以看到X.PagedList.Mvc.Core(7.5.0)程序包。
第3种:CLI命令行方式安装:dotnet add package X.PagedList.Mvc.Core --version 7.5.0
当使用X.PagedList.Mvc.Core 7.60版本的时候,PagedListRenderOptions类定义在了 X.PagedList.Mvc.Core.Common命名空间下,因此在视图需要改变默认的显示样式的时候,需要在视图上引入X.PagedList.Mvc.Core.Common命名空间。
第二步:使用X.PagedList.Mvc.Core.还是以微软ASP.NET MVC Core官方的例子。微软官方教程里面分页没有用到X.PagedList.Mvc.Core,而是自定义一个简单的分页类。
在控制器中,在IEnumerable/IQueryable对象调用 方法 .ToPagedList(page,pageSize)或..ToPagedListAsync(page,pageSize))将IEnumerable/IQueryable对象转换成IPagedList对象返加给视图。
在视图中,可以使用
1、@Html.PagedListPager(IPagedList list,Fun<int,string>GeneratePageUrl) 第一个参数为控制器返回的IpagedList对象,第二个参数是创建分页的URL。
2、或 @Htm.PagedListPager(IPagedList list,Fun<int,string>GeneratePageUrl,PagedListRenderOptions options) 此方法多了一个参数 PagedListRenderOptions,可以定义显示的格式。
在X.PagedList.Mvc.Core,IpagedList类型自带的返回给视图的分页参数有:
@Model.PageSize 指设置的是每页最大记录数,
@Model.TotalItemCount 总的记录数 ,
@Model.PageCount 总页数,
@Model.PageNumber 第几页,
@Model.Count() 当前页面上包含的记录数。
控制器代码:
@using X.PagedList; //引入命名空间
// GET: Students
public async Task<IActionResult> Index(string sortOrder,string searchString,int page =1,int pageSize=5) //默认每页最多显示5行记录
{
ViewData["CurrentSort"] = sortOrder;
ViewData["NameSortParm"] = string.IsNullOrEmpty(sortOrder) ? "name_desc" : "";
ViewData["DateSortParm"] = sortOrder == "date" ? "date_desc" : "date";
var students = from s in _context.Students
select s;
if (!string.IsNullOrEmpty(searchString))
{
students = students.Where(s => s.LastName.Contains(searchString) || s.FirstMidName.Contains(searchString));
}
ViewData["SearchString"] = searchString;
switch (sortOrder)
{
case "name_desc":
students = students.OrderByDescending(s => s.LastName);
break;
case "date":
students = students.OrderBy(s => s.EnrollmentDate);
break;
case "date_desc":
students = students.OrderByDescending(s => s.EnrollmentDate);
break;
default:
students = students.OrderBy(s => s.LastName);
break;
}
ViewData["PageSize"] = pageSize; //每页最多显示的记录数的返回给视图。以便在下次查询和排序的时候,每页也显示相同的记录数。
return View(await students.AsNoTracking().ToPagedListAsync(page,pageSize)); //执行异步方法;
}
视图:
@model X.PagedList.IPagedList<ContosoUniversity.Models.Student>
@using X.PagedList.Mvc.Core;
@X.PagedList.Mvc.Web.Common; //@using X.PagedList.Mvc.Web.Common; 7.6及以上版本需要引入Common命名空间,以支持PagedListRenderOptions .7.5以下的版本则不需要。
@{
ViewData["Title"] = "Index";
}
<link rel="stylesheet" href="~/css/PagedList.css" /> //将PagedList.css拷入程序css文件下,以便显示出支持Bootstrap4支格式的输出。
<h2>Index</h2>
<p>
<a asp-action="Create">Create New</a>
</p>
<form asp-action="Index" method="get" class="form-inline" role="form">
<label for="pageSize" class="control-label">每页指定记录数:</label>
<div class="form-group">
<input type="number" name="pageSize" id="pageSize" value="@ViewData["PageSize"]" class="form-control" size="1" maxlength="4" min="1" max="1000" /> //使用<input type="number">能保证输入的始终为数字,字符输不进去,但size和maxlength却失效了。text能保证文本框的宽度和能接受的字符数。 在<input type="number" min ="1" max="100">中,max决定了文本框的宽度。
@ 在<inputy type="text*>中, size属性用来设置显示文本框的宽度,在Bootstrap样式下同样实用,另外,maxlength用来设置文本框接受字符的个数,输多了输不进去。*@
</div>
<text> </text>
<label for="searchString" class="control-label">片名:</label>
<div class="form-group">
@Html.TextBox("searchString", ViewData["SearchString"] as string, htmlAttributes: new { @class = "form-control", placeHolder = "请输入片名" })
</div>
<text> </text>
<input type="submit" value="Search" class="btn btn-primary" />
<a asp-action="Index">Back to Full List</a>
</p>
</form>
<table class="table table-striped table-hover">
<thead>
<tr>
<th>
<a asp-action="Index" asp-route-sortOrder="@ViewData["NameSortParm"]" asp-route-searchString="@ViewData["SearchString"]" asp-route-pageSize="@ViewData["PageSize"]">LastName</a> //感觉TagHelper 还没有HtmlHelper在这里好用。
</th>
<th>
FirstMidName
</th>
<th>
<a asp-action="Index" asp-route-sortOrder="@ViewData["DateSortParm"]" asp-route-searchString="@ViewData["SearchString"]" asp-route-pageSize="@ViewData["PageSize"]">EnrollmentDate</a>
</th>
<th></th>
</tr>
</thead>
<tbody>
@foreach (var item in Model) {
<tr>
<td>
@Html.DisplayFor(modelItem => item.LastName)
</td>
<td>
@Html.DisplayFor(modelItem => item.FirstMidName)
</td>
<td>
@Html.DisplayFor(modelItem => item.EnrollmentDate)
</td>
<td>
<a asp-action="Edit" asp-route-id="@item.ID">Edit</a> |
<a asp-action="Details" asp-route-id="@item.ID">Details</a> |
<a asp-action="Delete" asp-route-id="@item.ID">Delete</a>
</td>
</tr>
}
</tbody>
<tfoot>
<tr>
<td class="text-muted" colspan="4">
每页 @Model.PageSize 条记录,本页有 @Model.Count 条记录,共有 @Model.TotalItemCount 条记录。第 @(Model.PageCount < Model.PageNumber ? 0 : Model.PageNumber) 页,共 @Model.PageCount 页。
@*这个条件表达式的目的是防止出现 记录为0的情况,会出现 总页数为0,而当前是第1页的情况。*@
</td>
</tr>
</tfoot>
</table>
@Html.PagedListPager(Model,page =>Url.Action("Index",new { page,sortOrder = ViewData["CurrentSort"], searchString = ViewData["SearchString"],pageSize=ViewData["PageSize"] }), new PagedListRenderOptions { LinkToFirstPageFormat = "首页", LinkToNextPageFormat = "下一页", LinkToPreviousPageFormat = "上一页", LinkToLastPageFormat = "末页", MaximumPageNumbersToDisplay = 5, DisplayItemSliceAndTotal = false })
Asp.NET Razor Pages 补充说明:
在RazorPages 中,不能使用 @Html.PagedListPager(Model.Students, page => Url.Action("Index", new { page})) 参数名称不能指定 为page, 如指定page,将不能正确创建 分页的链接。可能的原因是 page在Razor页面框架下有特定的含义,与之冲突。
1、可将参数page修改为pageIndex,@Html.PagedListPager(Model.Students, pageIndex => Url.Action("Index", new { pageIndex})) //在Razor Pages 中,URL.Action()也可以使用 URL.Page()来代替。
2、PageModel类也要作修改:
public async Task OnGetAsync(string sortOrder,string searchString,int pageIndex =1,int pageSize=3)
关于支持Bootstrap版本的问题:
目前的PagedList.Mvc.Corer 版本默认支持Bootstrap3,而最新的基架创建的引用的是 Bootstrap4, new PagedListRenderOptions 不能渲染分页按钮的样式。为了使用与Bootstrap 4和 Bootstrap 5默认的样式,因此,需要 指定 ul li 的样式。
Bootstrap 4 使用无序列表进行分页,样式为:
<ul class="pagination">
<li class="page-item"> <a class="page-link" href="#">Previous</a></li>
<li class="page-item"><a class="page-link" href="#">1</a></li>
<li class="page-item"><a class="page-link" href="#">2</a></li>
<li class="page-item"><a class="page-link" href="#">3</a></li>
<li class="page-item"><a class="page-link" href="#">Next</a></li>
</ul>
@Html.PagedListPager(Model.Students, page => Url.Action("Index", new { page, sortOrder = Model.CurrentSort, searchString = Model.CurrentFilter, pageSize = Model.PageSize }),
new PagedListRenderOptions
{
LinkToFirstPageFormat = "首页",
LinkToNextPageFormat = "下一页",
LinkToPreviousPageFormat = "上一页",
LinkToLastPageFormat = "末页",
MaximumPageNumbersToDisplay = 5,
DisplayItemSliceAndTotal = false,//从头到尾显示页码
UlElementClasses = new[] { "pagination"}, // 为ul li a 元素添加链接,使用ContainerDivClasses = new[] { "pagination" }替换 UlElementClasses = new[] { "pagination"},也是相同的效果。也可以不要此行代码,因为Bootstrap4与3相比,ul的class名没有变化,li 元素和a 元素加了page-item和page-link的类名。
LiElementClasses = new[] { "page-item" },
PageClasses = new[] { "page-link" },
})
可以使用X.PagedList.Mvc.Bootstrap4 包来替换X.PagedList.Mvc.Core。
Install-Package X.PagedList.Mvc.Bootstrap4
index.cshtml文件中的引用,
@using X.PagedList.Mvc.Core; //用以支持Html.PagedListPager方法
@using X.PagedList.Mvc.Bootstrap4.NetCore; // 用以支持 Bootstrap4PagedListRenderOptions ,能渲染成bootstrap4
@Html.PagedListPager(Model.Students, pageIndex => Url.Action("Index", new { pageIndex, sortOrder = Model.CurrentSort, searchString = Model.CurrentFilter, pageSize = Model.PageSize }),
Bootstrap4PagedListRenderOptions.ClassicPlusFirstAndLast)