简体   繁体   English

如何在 ASP.NET MVC 中进行分页?

[英]How do I do pagination in ASP.NET MVC?

What is the most preferred and easiest way to do pagination in ASP.NET MVC?在 ASP.NET MVC 中进行分页的最首选和最简单的方法是什么? Ie what is the easiest way to break up a list into several browsable pages.即什么是将列表分解为几个可浏览页面的最简单方法。

As an example lets say I get a list of elements from a database/gateway/repository like this:例如,假设我从数据库/网关/存储库中获取元素列表,如下所示:

public ActionResult ListMyItems()
{
    List<Item> list = ItemDB.GetListOfItems();
    ViewData["ItemList"] = list;

    return View();
}

For simplicity's sake I'd like to specify just a page number for my action as parameter.为简单起见,我只想为我的操作指定一个页码作为参数。 Like this:像这样:

public ActionResult ListMyItems(int page)
{
   //...
}

Well, what is the data source? 那么,什么是数据源? Your action could take a few defaulted arguments, ie 你的行动可以采取一些默认的论点,即

ActionResult Search(string query, int startIndex, int pageSize) {...}

defaulted in the routes setup so that startIndex is 0 and pageSize is (say) 20: 默认路由设置,以便startIndex为0,pageSize为(比方说)20:

        routes.MapRoute("Search", "Search/{query}/{startIndex}",
                        new
                        {
                            controller = "Home", action = "Search",
                            startIndex = 0, pageSize = 20
                        });

To split the feed, you can use LINQ quite easily: 要拆分Feed,您可以非常轻松地使用LINQ:

var page = source.Skip(startIndex).Take(pageSize);

(or do a multiplication if you use "pageNumber" rather than "startIndex") (如果使用“pageNumber”而不是“startIndex”,则进行乘法运算)

With LINQ-toSQL, EF, etc - this should "compose" down to the database, too. 使用LINQ-toSQL,EF等 - 这也应该“组合”到数据库。

You should then be able to use action-links to the next page (etc): 然后,您应该能够使用操作链接到下一页(等):

<%=Html.ActionLink("next page", "Search", new {
                query, startIndex = startIndex + pageSize, pageSize }) %>

I had the same problem and found a very elegant solution for a Pager Class from 我遇到了同样的问题,并为一个Pager Class找到了一个非常优雅的解决方案

http://blogs.taiga.nl/martijn/2008/08/27/paging-with-aspnet-mvc/ http://blogs.taiga.nl/martijn/2008/08/27/paging-with-aspnet-mvc/

In your controller the call looks like: 在您的控制器中,通话看起来像:

return View(partnerList.ToPagedList(currentPageIndex, pageSize));

and in your view: 在你看来:

<div class="pager">
    Seite: <%= Html.Pager(ViewData.Model.PageSize, 
                          ViewData.Model.PageNumber,
                          ViewData.Model.TotalItemCount)%>
</div>

I wanted to cover a simple way of doing this with the front end too: 我想通过前端介绍一种简单的方法:

Controller: 控制器:

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);
}

View: 视图:

@* 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>
}

Controller 调节器

 [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);
    }

BusinessLogic 商业逻辑

  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;
    }

View for displaying total page count 用于显示总页数的视图

 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>
        }
    }

I think the easiest way to create pagination in ASP.NET MVC application is using PagedList library. 我认为在ASP.NET MVC应用程序中创建分页的最简单方法是使用PagedList库。

There is a complete example in following github repository. 以下github存储库中有一个完整的示例。 Hope it would help. 希望它会有所帮助。

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();
    }
}

Demo Link: http://ajaxpagination.azurewebsites.net/ 演示链接: http//ajaxpagination.azurewebsites.net/

Source Code: https://github.com/ungleng/SimpleAjaxPagedListAndSearchMVC5 源代码: https//github.com/ungleng/SimpleAjaxPagedListAndSearchMVC5

Entity 实体

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 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>

Paging Logic 寻呼逻辑

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;
}

Using Controller 使用Controller

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);
}

Here's a link that helped me with this. 这是一个帮助我的链接

It uses PagedList.MVC NuGet package. 它使用PagedList.MVC NuGet包。 I'll try to summarize the steps 我将尝试总结这些步骤

  1. Install the PagedList.MVC NuGet package 安装PagedList.MVC NuGet包

  2. Build project 建立项目

  3. Add using PagedList; using PagedList; 添加 using PagedList; to the controller 到控制器

  4. Modify your action to set page public ActionResult ListMyItems(int? page) { List list = ItemDB.GetListOfItems(); int pageSize = 3; int pageNumber = (page ?? 1); return View(list.ToPagedList(pageNumber, pageSize)); } 修改你的动作以设置页面 public ActionResult ListMyItems(int? page) { List list = ItemDB.GetListOfItems(); int pageSize = 3; int pageNumber = (page ?? 1); return View(list.ToPagedList(pageNumber, pageSize)); } public ActionResult ListMyItems(int? page) { List list = ItemDB.GetListOfItems(); int pageSize = 3; int pageNumber = (page ?? 1); return View(list.ToPagedList(pageNumber, pageSize)); }

  5. Add paging links to the bottom of your view @*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 })) 将分页链接添加到视图的底部 @*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 }))

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>

It is possible to create a reusable pagination.可以创建可重复使用的分页。 What we need is:我们需要的是:

  • partial view to store number of pages and links to them部分视图来存储页数和指向它们的链接
  • reusable methods which contains pagination logic for IQueryable包含IQueryable分页逻辑的可重用方法

The complete example with source code can be seen here. 可以在此处查看带有源代码的完整示例。

So our code would like this:所以我们的代码是这样的:

The person table.人表。 I've used SQL Server:我使用过 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

I've used DatabaseFirst approach.我使用过 DatabaseFirst 方法。 This is a generated class by 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; }
}

This is a class which contains data and pagination information:这是一个包含数据和分页信息的类:

public class DataResultViewModel<T>
{
    /// <summary>
    /// Data items
    /// </summary>
    public IEnumerable<T> Items { get; set; }

    /// <summary>
    /// Pagination
    /// </summary>
    public Pagination Pagination { get; set; }
}

This is class which contains information about persons.这是包含有关人员信息的类。

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; }
}

and Pagination class:和分页类:

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; }
}

And the class which makes pagination.以及进行分页的类。 Basically, Skip() and Take () are methods which do a pagination, so we need to use these methods for all IQueryable .基本上, Skip()和 Take ()是进行分页的方法,因此我们需要对所有IQueryable使用这些方法。 And C# has a very neat feature called extension methods. C# 有一个非常简洁的特性,叫做扩展方法。 Extension methods allow to reuse code:扩展方法允许重用代码:

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);
    }
}

This is a class of service layer:这是一类服务层:

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;
        }
    }
}

And controller of person:和控制人:

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
                )
            );
    }
}

Then we should create views.然后我们应该创建视图。

This is a person view that should be paginated:这是一个应该分页的人视图:

@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>

And it is a reusable pagination partial view:它是一个可重用的分页部分视图:

@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>

That's all!就这样!

In the ASP .NET application to insert page pagination, first need to install Paged List and PagedList.MVC from the NuGet packages for the project.在 ASP .NET 应用程序中插入页面分页,首先需要从项目的 NuGet 包中安装 Paged List 和 PagedList.MVC。

Then I have included sample method which return the list of books from database.然后我包含了从数据库返回书籍列表的示例方法。 And I included the Page pagination to show 4 items in each page.我包括页面分页以在每个页面中显示 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));
    }

In the View page, this should be included.在查看页面中,这应该包括在内。

@Html.PagedListPager(Model, i => Url.Action("Books", "Library", new { i }))

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM