在以前的博文中寫過使用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.Core.Common; //@using X.PagedList.Mvc.Core.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 不能渲染分頁按鈕的樣式。因此,需要 指定 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)