Làm cách nào để phân trang trong ASP.NET MVC?


85

Cách ưu tiên nhất và dễ nhất để phân trang trong ASP.NET MVC là gì? Tức là cách dễ nhất để chia danh sách thành nhiều trang có thể duyệt.

Ví dụ, tôi có thể lấy danh sách các phần tử từ cơ sở dữ liệu / cổng / kho lưu trữ như sau:

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

    return View();
}

Vì lợi ích đơn giản, tôi chỉ muốn chỉ định một số trang cho hành động của tôi làm tham số. Như thế này:

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

Câu trả lời:


106

Nguồn dữ liệu là gì? Hành động của bạn có thể có một vài đối số được mặc định, tức là

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

được mặc định trong thiết lập các tuyến để startIndex là 0 và pageSize là (giả sử) 20:

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

Để chia nguồn cấp dữ liệu, bạn có thể sử dụng LINQ khá dễ dàng:

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

(hoặc thực hiện phép nhân nếu bạn sử dụng "pageNumber" thay vì "startIndex")

Với LINQ-toSQL, EF, v.v. - điều này cũng nên "biên soạn" xuống cơ sở dữ liệu.

Sau đó, bạn sẽ có thể sử dụng các liên kết hành động đến trang tiếp theo (v.v.):

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

3
Đó là một ví dụ định tuyến thú vị, vì vậy tôi sẽ ủng hộ nó. Tôi vẫn chưa hiểu rõ về việc sử dụng LINQ, vì vậy Skip and Take là điều mới mẻ đối với tôi. Nhưng đó chắc chắn là những gì tôi cần. Và đó là lý do tại sao tôi sẽ đánh dấu đây là câu trả lời.
Spoike

thứ tuyệt vời! Cảm ơn bạn rất nhiều trong hành động.
Ric Tokyo

Khi sử dụng MVC2, ActionLinkcú pháp của bạn đang khiến tôi gặp lỗi Biên dịch khi yêu cầu trang. CS0103: Tên 'startIndex' không tồn tại trong ngữ cảnh hiện tại. Kỹ thuật này không thực hiện được với MVC2?
comecme 10/12/12

@comecme ý bạn là dòng cuối cùng? bạn cần cung cấp các giá trị (hoặc biến) đó. Có gì có sự khởi đầu-index / trang-kích thước?
Marc Gravell

1
Vâng, ý tôi là dòng cuối cùng. Tôi nghĩ rằng bạn đang sử dụng hiện tại startIndexvà thêm pageSizevào nó. Tôi hy vọng nó sẽ tự động sử dụng các giá trị của lần gọi cuối cùng Search. Làm thế nào tôi sẽ sử dụng startIndextừ cuối cùng Searchtrong của tôi ActionLink?
comecme 10/12/12

16

Tôi đã gặp vấn đề tương tự và tìm thấy một giải pháp rất hữu ích cho Lớp máy nhắn tin từ

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

Trong bộ điều khiển của bạn, cuộc gọi trông giống như:

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

và theo quan điểm của bạn:

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

Nó dành cho ASP.NET MVC Preview 5. Nó sẽ hoạt động cho ASP.NET MVC Beta?
Spoike

Liên kết đã thay đổi, mã được cập nhật thành RC1 (đoán nó cũng sẽ hoạt động với 1.0, sẽ thử ngay bây giờ). blogs.taiga.nl/martijn/2008/08/27/paging-with-aspnet-mvc
Palantir

16

Tôi cũng muốn trình bày một cách đơn giản để thực hiện việc này với giao diện người dùng:

Bộ điều khiển:

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

Lượt xem:

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

3
var data = this.dataSource.Skip(page * PageSize).Take(PageSize).ToList();Yêu cầu một orderBy(o => o.Id)trước khi bạn có thể sử dụng skip()|| Bên cạnh đó, đây là một câu trả lời tuyệt vời xứng đáng được nhiều lượt ủng hộ hơn.
Vahx

4

Đây là một liên kết đã giúp tôi với điều này.

Nó sử dụng gói PagedList.MVC NuGet. Tôi sẽ cố gắng tóm tắt các bước

  1. Cài đặt gói PagedList.MVC NuGet

  2. Xây dựng dự án

  3. Thêm using PagedList; vào bộ điều khiển

  4. Sửa đổi hành động của bạn để thiết lập trang public ActionResult ListMyItems(int? page) { List list = ItemDB.GetListOfItems(); int pageSize = 3; int pageNumber = (page ?? 1); return View(list.ToPagedList(pageNumber, pageSize)); }

  5. Thêm liên kết phân trang vào cuối chế độ xem của bạn @*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 }))


1
Tôi biết đây là một câu hỏi cũ, đó là lý do tại sao câu trả lời này không có nhiều lượt ủng hộ. Nhưng nó nên vì đây là giải pháp hiện đại tốt nhất. PagedList Demo
omgGenerics

2

Bộ điều khiển

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

Xem để hiển thị tổng số trang

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

2

Tôi nghĩ rằng cách dễ nhất để tạo phân trang trong ứng dụng ASP.NET MVC là sử dụng thư viện PagedList.

Có một ví dụ đầy đủ trong kho lưu trữ github sau đây. Hy vọng nó sẽ hữu ích.

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

Liên kết Demo: http://ajaxpagination.azurewebsites.net/

Mã nguồn: https://github.com/ungleng/SimpleAjaxPagedListAndSearchMVC5


1

Thực thể

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>

Phân trang 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;
}

Sử dụng bộ điều khiển

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

Lớp "Place" là gì?
FreeVice

1
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>
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.