如何在 ASP.NET MVC 中进行分页?
Posted
技术标签:
【中文标题】如何在 ASP.NET MVC 中进行分页?【英文标题】:How do I do pagination in ASP.NET MVC? 【发布时间】:2010-10-01 13:33:27 【问题描述】:在 ASP.NET MVC 中进行分页的最首选和最简单的方法是什么? IE。将列表分成几个可浏览页面的最简单方法是什么。
例如,假设我从数据库/网关/存储库中获取元素列表,如下所示:
public ActionResult ListMyItems()
List<Item> list = ItemDB.GetListOfItems();
ViewData["ItemList"] = list;
return View();
为简单起见,我只想为我的操作指定一个页码作为参数。像这样:
public ActionResult ListMyItems(int page)
//...
【问题讨论】:
【参考方案1】:那么,数据源是什么?您的操作可能需要一些默认参数,即
ActionResult Search(string query, int startIndex, int pageSize) ...
在路由设置中默认为 startIndex 为 0,pageSize 为(比如说)20:
routes.MapRoute("Search", "Search/query/startIndex",
new
controller = "Home", action = "Search",
startIndex = 0, pageSize = 20
);
要拆分提要,您可以很容易地使用 LINQ:
var page = source.Skip(startIndex).Take(pageSize);
(如果您使用“pageNumber”而不是“startIndex”,则进行乘法运算)
使用 LINQ-toSQL、EF 等 - 这也应该“组合”到数据库。
然后您应该能够使用操作链接到下一页(等):
<%=html.ActionLink("next page", "Search", new
query, startIndex = startIndex + pageSize, pageSize ) %>
【讨论】:
这是一个有趣的路由示例,所以我会支持它。我还没有开始使用 LINQ,所以 Skip and Take 对我来说是新的。但这绝对是我需要的。这就是我将其标记为答案的原因。 好东西!非常感谢你。 使用 MVC2,您的ActionLink
语法在请求页面时给了我一个编译错误。 CS0103:当前上下文中不存在名称“startIndex”。这种技术在 MVC2 中是不可能的吗?
@comecme 你的意思是最后一行吗?您需要提供这些值(或变量)。起始索引/页面大小是是多少?
是的,我的意思是最后一行。我以为您正在使用当前的startIndex
并添加pageSize
。我希望它会自动使用上次调用Search
的值。我将如何在我的ActionLink
中使用最后一个Search
中的startIndex
?【参考方案2】:
我也想用前端介绍一种简单的方法:
控制器:
public ActionResult Index(int page = 0)
const int PageSize = 3; // you can always do something more elegant to set this
var count = this.dataSource.Count();
var data = this.dataSource.Skip(page * PageSize).Take(PageSize).ToList();
this.ViewBag.MaxPage = (count / PageSize) - (count % PageSize == 0 ? 1 : 0);
this.ViewBag.Page = page;
return this.View(data);
查看:
@* rest of file with view *@
@if (ViewBag.Page > 0)
<a href="@Url.Action("Index", new page = ViewBag.Page - 1 )"
class="btn btn-default">
« Prev
</a>
@if (ViewBag.Page < ViewBag.MaxPage)
<a href="@Url.Action("Index", new page = ViewBag.Page + 1 )"
class="btn btn-default">
Next »
</a>
【讨论】:
var data = this.dataSource.Skip(page * PageSize).Take(PageSize).ToList();
需要orderBy(o => o.Id)
才能使用skip()
||除此之外,这是一个很好的答案,值得更多的支持。
很好的答案!如果你想让页面从 1 而不是 0 开始,使用这个: var data = this.dataSource.Skip((page - 1) * PageSize).Take(PageSize).ToList();【参考方案3】:
我遇到了同样的问题,并为 Pager Class 找到了一个非常优雅的解决方案
http://blogs.taiga.nl/martijn/2008/08/27/paging-with-aspnet-mvc/
在您的控制器中,调用如下所示:
return View(partnerList.ToPagedList(currentPageIndex, pageSize));
在你看来:
<div class="pager">
Seite: <%= Html.Pager(ViewData.Model.PageSize,
ViewData.Model.PageNumber,
ViewData.Model.TotalItemCount)%>
</div>
【讨论】:
适用于 ASP.NET MVC Preview 5。它适用于 ASP.NET MVC Beta 吗? 链接已更改,代码已更新为 RC1(猜想它也适用于 1.0,现在将试用)。 blogs.taiga.nl/martijn/2008/08/27/paging-with-aspnet-mvc【参考方案4】:这里是 a link,它帮助了我。
它使用 PagedList.MVC NuGet 包。我会尝试总结步骤
安装 PagedList.MVC NuGet 包
构建项目
添加 using PagedList;
到控制器
修改您的操作以设置页面
public ActionResult ListMyItems(int? page)
List list = ItemDB.GetListOfItems();
int pageSize = 3;
int pageNumber = (page ?? 1);
return View(list.ToPagedList(pageNumber, pageSize));
在视图底部添加分页链接
@*Your existing view*@
Page @(Model.PageCount < Model.PageNumber ? 0 : Model.PageNumber) of @Model.PageCount
@Html.PagedListPager(Model, page => Url.Action("Index",
new page, sortOrder = ViewBag.CurrentSort, currentFilter = ViewBag.CurrentFilter ))
【讨论】:
我知道这是一个老问题,这就是为什么这个答案没有很多赞成票的原因。但它应该是因为这是最好的现代解决方案。 PagedList Demo【参考方案5】:控制器
[HttpGet]
public async Task<ActionResult> Index(int page =1)
if (page < 0 || page ==0 )
page = 1;
int pageSize = 5;
int totalPage = 0;
int totalRecord = 0;
BusinessLayer bll = new BusinessLayer();
MatchModel matchmodel = new MatchModel();
matchmodel.GetMatchList = bll.GetMatchCore(page, pageSize, out totalRecord, out totalPage);
ViewBag.dbCount = totalPage;
return View(matchmodel);
业务逻辑
public List<Match> GetMatchCore(int page, int pageSize, out int totalRecord, out int totalPage)
SignalRDataContext db = new SignalRDataContext();
var query = new List<Match>();
totalRecord = db.Matches.Count();
totalPage = (totalRecord / pageSize) + ((totalRecord % pageSize) > 0 ? 1 : 0);
query = db.Matches.OrderBy(a => a.QuestionID).Skip(((page - 1) * pageSize)).Take(pageSize).ToList();
return query;
显示总页数的视图
if (ViewBag.dbCount != null)
for (int i = 1; i <= ViewBag.dbCount; i++)
<ul class="pagination">
<li>@Html.ActionLink(@i.ToString(), "Index", "Grid", new page = @i ,null)</li>
</ul>
【讨论】:
【参考方案6】:我认为在 ASP.NET MVC 应用程序中创建分页的最简单方法是使用 PagedList 库。
在下面的 github 仓库中有一个完整的例子。希望它会有所帮助。
public class ProductController : Controller
public object Index(int? page)
var list = ItemDB.GetListOfItems();
var pageNumber = page ?? 1;
var onePageOfItem = list.ToPagedList(pageNumber, 25); // will only contain 25 items max because of the pageSize
ViewBag.onePageOfItem = onePageOfProducts;
return View();
演示链接:http://ajaxpagination.azurewebsites.net/
源代码:https://github.com/ungleng/SimpleAjaxPagedListAndSearchMVC5
【讨论】:
【参考方案7】:实体
public class PageEntity
public int Page get; set;
public string Class get; set;
public class Pagination
public List<PageEntity> Pages get; set;
public int Next get; set;
public int Previous get; set;
public string NextClass get; set;
public string PreviousClass get; set;
public bool Display get; set;
public string Query get; set;
HTML
<nav>
<div class="navigation" style="text-align: center">
<ul class="pagination">
<li class="page-item @Model.NextClass"><a class="page-link" href="?page=@(@Model.Previous+@Model.Query)">«</a></li>
@foreach (var item in @Model.Pages)
<li class="page-item @item.Class"><a class="page-link" href="?page=@(item.Page+@Model.Query)">@item.Page</a></li>
<li class="page-item @Model.NextClass"><a class="page-link" href="?page=@(@Model.Next+@Model.Query)">»</a></li>
</ul>
</div>
</nav>
分页逻辑
public Pagination GetCategoryPaging(int currentPage, int recordCount, string query)
string pageClass = string.Empty; int pageSize = 10, innerCount = 5;
Pagination pagination = new Pagination();
pagination.Pages = new List<PageEntity>();
pagination.Next = currentPage + 1;
pagination.Previous = ((currentPage - 1) > 0) ? (currentPage - 1) : 1;
pagination.Query = query;
int totalPages = ((int)recordCount % pageSize) == 0 ? (int)recordCount / pageSize : (int)recordCount / pageSize + 1;
int loopStart = 1, loopCount = 1;
if ((currentPage - 2) > 0)
loopStart = (currentPage - 2);
for (int i = loopStart; i <= totalPages; i++)
pagination.Pages.Add(new PageEntity Page = i, Class = string.Empty );
if (loopCount == innerCount)
break;
loopCount++;
if (totalPages <= innerCount)
pagination.PreviousClass = "disabled";
foreach (var item in pagination.Pages.Where(x => x.Page == currentPage))
item.Class = "active";
if (pagination.Pages.Count() <= 1)
pagination.Display = false;
return pagination;
使用控制器
public ActionResult GetPages()
int currentPage = 1; string search = string.Empty;
if (!string.IsNullOrEmpty(Request.QueryString["page"]))
currentPage = Convert.ToInt32(Request.QueryString["page"]);
if (!string.IsNullOrEmpty(Request.QueryString["q"]))
search = "&q=" + Request.QueryString["q"];
/* to be Fetched from database using count */
int recordCount = 100;
Place place = new Place();
Pagination pagination = place.GetCategoryPaging(currentPage, recordCount, search);
return PartialView("Controls/_Pagination", pagination);
【讨论】:
什么是“Place”类?【参考方案8】:public ActionResult Paging(int? pageno,bool? fwd,bool? bwd)
if(pageno!=null)
Session["currentpage"] = pageno;
using (HatronEntities DB = new HatronEntities())
if(fwd!=null && (bool)fwd)
pageno = Convert.ToInt32(Session["currentpage"]) + 1;
Session["currentpage"] = pageno;
if (bwd != null && (bool)bwd)
pageno = Convert.ToInt32(Session["currentpage"]) - 1;
Session["currentpage"] = pageno;
if (pageno==null)
pageno = 1;
if(pageno<0)
pageno = 1;
int total = DB.EmployeePromotion(0, 0, 0).Count();
int totalPage = (int)Math.Ceiling((double)total / 20);
ViewBag.pages = totalPage;
if (pageno > totalPage)
pageno = totalPage;
return View (DB.EmployeePromotion(0,0,0).Skip(GetSkip((int)pageno,20)).Take(20).ToList());
private static int GetSkip(int pageIndex, int take)
return (pageIndex - 1) * take;
@model IEnumerable<EmployeePromotion_Result>
@
Layout = null;
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width" />
<title>Paging</title>
</head>
<body>
<div>
<table border="1">
@foreach (var itm in Model)
<tr>
<td>@itm.District</td>
<td>@itm.employee</td>
<td>@itm.PromotionTo</td>
</tr>
</table>
<a href="@Url.Action("Paging", "Home",new pageno=1 )">First page</a>
<a href="@Url.Action("Paging", "Home", new bwd =true )"><<</a>
@for(int itmp =1; itmp< Convert.ToInt32(ViewBag.pages)+1;itmp++)
<a href="@Url.Action("Paging", "Home",new pageno=itmp )">@itmp.ToString()</a>
<a href="@Url.Action("Paging", "Home", new fwd = true )">>></a>
<a href="@Url.Action("Paging", "Home", new pageno = Convert.ToInt32(ViewBag.pages) )">Last page</a>
</div>
</body>
</html>
【讨论】:
【参考方案9】:可以创建可重复使用的分页。我们需要的是:
部分视图用于存储页面数量和指向它们的链接 包含IQueryable
的分页逻辑的可重用方法
The complete example with source code can be seen here.
所以我们的代码是这样的:
人员表。我用过 SQL Server:
IF NOT EXISTS
(
SELECT 1
FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = 'Person'
AND TABLE_SCHEMA = 'dbo'
)
BEGIN
CREATE TABLE dbo.Person
(
ID INT IDENTITY(1, 1) NOT NULL PRIMARY KEY
, CreateDate DATETIME NOT NULL DEFAULT GETDATE()
, Creator VARCHAR(100) NOT NULL
, ModifyDate DATETIME NULL
, Modifier VARCHAR(20) NULL
, FirstName VARCHAR(150) NOT NULL
, LastName VARCHAR(1000) NOT NULL
)
ON [PRIMARY]
END
GO
我使用了 DatabaseFirst 方法。这是 Entity Framework 生成的类。
public partial class Person
public int ID get; set;
public System.DateTime CreateDate get; set;
public string Creator get; set;
public string FirstName get; set;
public string LastName get; set;
public Nullable<System.DateTime> ModifyDate get; set;
public string Modifier get; set;
这是一个包含数据和分页信息的类:
public class DataResultViewModel<T>
/// <summary>
/// Data items
/// </summary>
public IEnumerable<T> Items get; set;
/// <summary>
/// Pagination
/// </summary>
public Pagination Pagination get; set;
这是包含有关人员信息的类。
public class PersonViewModel
public int ID get; set;
public string FirstName get; set;
public string LastName get; set;
/// <summary>
/// What route should be requested while paging
/// </summary>
public class RouteInfo
/// <summary>
/// Name of controller
/// </summary>
public string ControllerName get; set;
/// <summary>
/// Name of action
/// </summary>
public string ActionName get; set;
和分页类:
public class Pagination
/// <summary>
/// Total count of items
/// </summary>
public int TotalItems get; set;
/// <summary>
/// Count of items at the page
/// </summary>
public int PageSize get; set; = 5;
/// <summary>
/// Current page
/// </summary>
public int Page get; set;
/// <summary>
/// Sorted by field name
/// </summary>
public string SortBy get; set;
/// <summary>
/// Is this an ascending sort?
/// </summary>
public bool IsSortAscending get; set;
/// <summary>
/// Information about what page should be requested
/// </summary>
public RouteInfo RouteInfo get; set;
以及进行分页的类。基本上,Skip()
和 Take()
是进行分页的方法,所以我们需要对所有IQueryable
使用这些方法。 C# 有一个非常简洁的特性,叫做扩展方法。扩展方法允许重用代码:
public static class IQueryableExtension
public static IQueryable<T> UseOrdering<T, TResultSelector>(this IQueryable<T> query,
Pagination pagination,
Expression<Func<T, TResultSelector>> field)
if (string.IsNullOrWhiteSpace(pagination.SortBy)
|| string.IsNullOrEmpty(pagination.SortBy))
return query;
return pagination.IsSortAscending ?
query.OrderBy(field) :
query.OrderByDescending(field);
public static IQueryable<T> UsePagination<T>(this IQueryable<T> query,
Pagination pagination)
if (pagination.Page <= 0)
pagination.Page = 1;
if (pagination.PageSize <= 0)
pagination.PageSize = 10;
return query.Skip((pagination.Page - 1) * pagination.PageSize)
.Take(pagination.PageSize);
这是一类服务层:
public class PersonService
public DataResultViewModel<PersonViewModel> GetWithPagination(Pagination pagination,
Expression<Func<Person, DateTime>> fieldName)
var result = new DataResultViewModel<PersonViewModel>();
using (var db = new MiscellaneousEntities())
var persons = db.Person.AsQueryable();
result.Pagination = pagination;
result.Pagination.TotalItems = persons.Count();
result.Pagination.RouteInfo = new RouteInfo()
ActionName = "Index",
ControllerName = "Person"
;
if (pagination.SortBy == null)
pagination.SortBy = "CreateDate";
persons = persons.UseOrdering(pagination, fieldName);
persons = persons.UsePagination(pagination);
result.Items = persons
.Select(s => new PersonViewModel()
ID = s.ID,
FirstName = s.FirstName,
LastName = s.LastName
)
.ToList();
return result;
及控制人:
public class PersonController : Controller
PersonService _personService;
public PersonController()
_personService = new PersonService();
// GET: Person
public ActionResult Index(int? page, int? pageSize, string sortBy,
bool? isSortAscending)
return View
(_personService.GetWithPagination(new Pagination()
Page = page ?? 1,
PageSize = pageSize ?? 3,
SortBy = sortBy,
IsSortAscending = isSortAscending ?? false
,
v => v.CreateDate
)
);
那么我们应该创建视图。
这是一个应该分页的人物视图:
@model OnlyPagination.ViewModel.DataResultViewModel<OnlyPagination.ViewModel.PersonViewModel>
<div class="d-flex justify-content-center">
<div>
@foreach (var item in Model.Items)
<div>
<p>Id is @item.ID</p>
<p>FirstName is @item.FirstName</p>
<p>LastName is @item.LastName</p>
</div>
<hr />
</div>
</div>
<div class="d-flex justify-content-center">
@
@Html.Partial("Pagination", Model.Pagination)
</div>
而且是可复用的分页局部视图:
@model OnlyPagination.Extensions.Query.Model.Pagination
@
var pagesCount = Math.Ceiling((decimal)Model.TotalItems / (decimal)Model.PageSize);
var pages = new List<int>();
for (var i = 1; i <= pagesCount; i++)
pages.Add(i);
<div>
<p class="d-flex justify-content-center">Page @Model.Page of @pagesCount</p>
<ul class="pagination">
<li class="page-item @( Model.Page == 1 ? "disabled" : "" )">
<a aria-label="Previous" class="page-link"
href="@Url.Action
(Model.RouteInfo.ActionName, Model.RouteInfo.ControllerName,
new page = Model.Page - 1, pageSize = Model.PageSize )">
<span aria-hidden="true">«</span>
</a>
</li>
@for (int pageNumber = 1; pageNumber <= pages.Count; pageNumber++)
<li class="page-item @( Model.Page == pageNumber ? "active" : "" )">
<a class="page-link"
href="@Url.Action(Model.RouteInfo.ActionName,
Model.RouteInfo.ControllerName,
new page = pageNumber, pageSize = Model.PageSize )">
@pageNumber </a>
</li>
<li class="page-item @(Model.Page == pages.Count ? "disabled" : "")">
<a aria-label="Next" class="page-link"
href="@Url.Action
(Model.RouteInfo.ActionName, Model.RouteInfo.ControllerName,
new page = Model.Page + 1, pageSize = Model.PageSize )">
<span aria-hidden="true">»</span>
</a>
</li>
</ul>
</div>
就是这样!
【讨论】:
【参考方案10】:在 ASP .NET 应用程序中插入页面分页,首先需要从项目的 NuGet 包中安装 Paged List 和 PagedList.MVC。
然后我包含了从数据库返回书籍列表的示例方法。并且我包含了页面分页以在每个页面中显示 4 个项目。
public ActionResult Books(int? i)
IEnumerable<Books> BooksList;
HttpResponseMessage response = GlobalVariables.webApiClient.GetAsync("Tbl_Books").Result;
BooksList = response.Content.ReadAsAsync<IEnumerable<Books>>().Result;
return View(BooksList.ToList().ToPagedList(i ?? 1, 4));
在“查看”页面中,应包含此内容。
@Html.PagedListPager(Model, i => Url.Action("Books", "Library", new i ))
【讨论】:
以上是关于如何在 ASP.NET MVC 中进行分页?的主要内容,如果未能解决你的问题,请参考以下文章
MvcPager 概述 MvcPager 分页示例 — 标准Ajax分页 对SEO进行优化的ajax分页 (支持asp.net mvc)