【问题标题】:How do I do pagination in ASP.NET MVC?如何在 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)
{
   //...
}

【问题讨论】:

    标签: c# asp.net asp.net-mvc


    【解决方案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>
    

    【讨论】:

    【解决方案4】:

    这里是 a link,它帮助了我。

    它使用 PagedList.MVC NuGet 包。我会尝试总结步骤

    1. 安装 PagedList.MVC NuGet 包

    2. 构建项目

    3. 添加 using PagedList; 到控制器

    4. 修改您的操作以设置页面 public ActionResult ListMyItems(int? page) { List list = ItemDB.GetListOfItems(); int pageSize = 3; int pageNumber = (page ?? 1); return View(list.ToPagedList(pageNumber, pageSize)); }

    5. 在视图底部添加分页链接 @*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 }))
            

            【讨论】:

              猜你喜欢
              • 2016-10-11
              • 2020-12-22
              • 1970-01-01
              • 1970-01-01
              • 2013-09-18
              • 1970-01-01
              • 2020-04-04
              • 2010-12-17
              • 2021-03-12
              相关资源
              最近更新 更多