Jak zrobić paginację w ASP.NET MVC?


85

Jaki jest najbardziej preferowany i najłatwiejszy sposób stronicowania w ASP.NET MVC? To jest najłatwiejszy sposób podzielenia listy na kilka stron, które można przeglądać.

Jako przykład powiedzmy, że otrzymuję listę elementów z bazy danych / bramy / repozytorium w następujący sposób:

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

    return View();
}

Dla uproszczenia chciałbym jako parametr podać tylko numer strony dla mojej akcji. Lubię to:

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

Odpowiedzi:


106

Jakie jest źródło danych? Twoja akcja może przyjąć kilka domyślnych argumentów, tj

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

domyślnie w konfiguracji tras, tak że startIndex ma wartość 0, a pageSize to (powiedzmy) 20:

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

Aby podzielić kanał, możesz dość łatwo użyć LINQ:

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

(lub pomnóż, jeśli używasz „pageNumber” zamiast „startIndex”)

Z LINQ-toSQL, EF itp. - powinno to również „komponować” do bazy danych.

Powinieneś wtedy móc użyć linków do akcji do następnej strony (itp.):

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

3
To interesujący przykład routingu, więc zagłosuję za nim. Nie wdałem się jeszcze w rytm korzystania z LINQ, więc Skip and Take to dla mnie nowość. Ale to jest zdecydowanie to, czego potrzebuję. Dlatego oznaczę to jako odpowiedź.
Spoike

niesamowite rzeczy! Na prawdę bardzo ci dziękuję.
Ric Tokyo,

Używając MVC2, twoja ActionLinkskładnia daje mi błąd kompilacji podczas żądania strony. CS0103: Nazwa „startIndex” nie istnieje w bieżącym kontekście. Czy ta technika nie jest możliwa w przypadku MVC2?
przyjdź

@comecme czy masz na myśli ostatnią linię? musisz podać te wartości (lub zmienne). Jaki jest ten indeks początkowy / rozmiar strony?
Marc Gravell

1
Tak, mam na myśli ostatnią linijkę. Myślałem, że używasz prądu startIndexi dodajesz pageSizedo niego. Miałem nadzieję, że automatycznie użyje wartości ostatniego wywołania Search. Jak użyłbym startIndexod ostatniego Searchw moim ActionLink?
przyjdź

16

Miałem ten sam problem i znalazłem bardzo eleganckie rozwiązanie dla klasy pager z

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

W twoim kontrolerze wywołanie wygląda następująco:

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

i Twoim zdaniem:

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

Dotyczy ASP.NET MVC w wersji zapoznawczej 5. Czy będzie działać w przypadku ASP.NET MVC Beta?
Spoike

Link zmieniony, kod zaktualizowany do RC1 (przypuszczam, że będzie działał również z 1.0, teraz zostanie wypróbowany). blogs.taiga.nl/martijn/2008/08/27/paging-with-aspnet-mvc
Palantir

16

Chciałem omówić prosty sposób zrobienia tego również z przodu:

Kontroler:

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

Widok:

@* 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();Wymaga orderBy(o => o.Id)przed użyciem skip()|| Poza tym jest to świetna odpowiedź, która zasługuje na dużo więcej głosów.
Vahx

4

Oto link, który mi w tym pomógł.

Używa pakietu PagedList.MVC NuGet. Spróbuję podsumować kroki

  1. Zainstaluj pakiet PagedList.MVC NuGet

  2. Zbuduj projekt

  3. Dodaj using PagedList; do kontrolera

  4. Zmodyfikuj swoje działanie, aby ustawić stronę public ActionResult ListMyItems(int? page) { List list = ItemDB.GetListOfItems(); int pageSize = 3; int pageNumber = (page ?? 1); return View(list.ToPagedList(pageNumber, pageSize)); }

  5. Dodaj linki stronicowania u dołu widoku @*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
Wiem, że to stare pytanie, dlatego ta odpowiedź nie ma wielu głosów za. Ale powinno, bo to najlepsze nowoczesne rozwiązanie. PagedList Demo
omgGenerics

2

Kontroler

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

Logika biznesowa

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

Widok do wyświetlania całkowitej liczby stron

 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

Myślę, że najłatwiejszym sposobem tworzenia stronicowania w aplikacji ASP.NET MVC jest użycie biblioteki PagedList.

Kompletny przykład znajduje się w następującym repozytorium github. Mam nadzieję, że to pomoże.

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

Link do wersji demonstracyjnej: http://ajaxpagination.azurewebsites.net/

Kod źródłowy: https://github.com/ungleng/SimpleAjaxPagedListAndSearchMVC5


1

Jednostka

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>

Logika stronicowania

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

Korzystanie z kontrolera

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

Co to jest klasa „Miejsce”?
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>
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.