Come si esegue l'impaginazione in ASP.NET MVC?


85

Qual è il modo più preferito e più semplice per eseguire l'impaginazione in ASP.NET MVC? Vale a dire qual è il modo più semplice per suddividere un elenco in più pagine sfogliabili.

Ad esempio, diciamo che ottengo un elenco di elementi da un database / gateway / repository come questo:

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

    return View();
}

Per semplicità vorrei specificare solo un numero di pagina per la mia azione come parametro. Come questo:

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

Risposte:


107

Ebbene, qual è la fonte dei dati? La tua azione potrebbe richiedere alcuni argomenti predefiniti, ad es

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

predefinito nella configurazione delle rotte in modo che startIndex sia 0 e pageSize sia (diciamo) 20:

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

Per dividere il feed, puoi usare LINQ abbastanza facilmente:

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

(o fai una moltiplicazione se usi "pageNumber" invece di "startIndex")

Con LINQ-toSQL, EF, ecc., Anche questo dovrebbe "comporre" fino al database.

Dovresti quindi essere in grado di utilizzare i link di azione alla pagina successiva (ecc.):

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

3
Questo è un interessante esempio di routing, quindi lo voterò a favore. Non sono ancora entrato nel solco dell'uso di LINQ, quindi Skip and Take è una novità per me. Ma è decisamente quello di cui ho bisogno. Ed è per questo che lo contrassegno come risposta.
Spoike

roba stupenda! Molte grazie.
Ric Tokyo

Utilizzando MVC2, la tua ActionLinksintassi mi dà un errore di compilazione quando richiedo la pagina. CS0103: il nome "startIndex" non esiste nel contesto corrente. Questa tecnica non è possibile con MVC2?
comecme il

@comecme, intendi l'ultima riga? è necessario fornire quei valori (o variabili). Che cosa è che start-index / page-size?
Marc Gravell

1
Sì, intendo l'ultima riga. Pensavo stessi usando la corrente startIndexe aggiungendola pageSize. Speravo che usasse automaticamente i valori dell'ultima chiamata a Search. Come userei startIndexl'ultimo Searchnel mio ActionLink?
comecme il

16

Ho avuto lo stesso problema e ho trovato una soluzione molto elegante per una classe Pager da

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

Nel controller la chiamata ha il seguente aspetto:

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

e secondo te:

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

È per ASP.NET MVC Preview 5. Funzionerà per ASP.NET MVC Beta?
Spoike

Collegamento cambiato, codice aggiornato a RC1 (suppongo che funzionerà anche con 1.0, lo proverò ora). blogs.taiga.nl/martijn/2008/08/27/paging-with-aspnet-mvc
Palantir

16

Volevo coprire un modo semplice per farlo anche con il front-end:

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

Visualizza:

@* 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();Richiede un orderBy(o => o.Id)prima di poter usare skip()|| Oltre a ciò questa è un'ottima risposta che merita molti più voti positivi.
Vahx

4

Ecco un collegamento che mi ha aiutato con questo.

Usa il pacchetto PagedList.MVC NuGet. Cercherò di riassumere i passaggi

  1. Installa il pacchetto PagedList.MVC NuGet

  2. Costruisci progetto

  3. Aggiungi using PagedList; al controller

  4. Modifica la tua azione per impostare la pagina public ActionResult ListMyItems(int? page) { List list = ItemDB.GetListOfItems(); int pageSize = 3; int pageNumber = (page ?? 1); return View(list.ToPagedList(pageNumber, pageSize)); }

  5. Aggiungi collegamenti di paging nella parte inferiore della visualizzazione @*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
So che questa è una vecchia domanda, motivo per cui questa risposta non ha molti voti positivi. Ma dovrebbe poiché questa è la migliore soluzione moderna. PagedList Demo
omgGenerics

2

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

Logica di business

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

Visualizza per visualizzare il conteggio totale delle pagine

 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

Penso che il modo più semplice per creare l'impaginazione nell'applicazione ASP.NET MVC sia usare la libreria PagedList.

C'è un esempio completo nel seguente repository github. Spero possa aiutare.

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 demo: http://ajaxpagination.azurewebsites.net/

Codice sorgente: https://github.com/ungleng/SimpleAjaxPagedListAndSearchMVC5


1

Entità

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>

Logica di paging

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

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

Cos'è la classe "Place"?
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>
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.