如何在 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">
        &laquo; Prev
    </a>

@if (ViewBag.Page < ViewBag.MaxPage)

    <a href="@Url.Action("Index", new  page = ViewBag.Page + 1 )" 
       class="btn btn-default">
        Next &raquo;
    </a>

【讨论】:

var data = this.dataSource.Skip(page * PageSize).Take(PageSize).ToList(); 需要orderBy(o =&gt; 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)">&laquo;</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)">&raquo;</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">&laquo;</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">&raquo;</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)

在 asp.net MVC 中对表进行排序

在使用asp.net mvc查询时候的分页

Asp.net MVC 4 / 5 中的分页

如何在 ASP.net Core 中实现 dataTables 服务器端分页/搜索/排序

如何在 ASP.NET MVC 6 中注册 ILogger 以进行注入