Comment faire la pagination dans ASP.NET MVC?

85

Quelle est la manière la plus préférée et la plus simple d'effectuer la pagination dans ASP.NET MVC? C'est-à-dire quel est le moyen le plus simple de diviser une liste en plusieurs pages consultables.

À titre d'exemple, disons que j'obtiens une liste d'éléments d'une base de données / d'une passerelle / d'un référentiel comme ceci:

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

    return View();
}

Par souci de simplicité, j'aimerais spécifier simplement un numéro de page pour mon action en tant que paramètre. Comme ça:

public ActionResult ListMyItems(int page)
{
   //...
}
Spoike
la source

Réponses:

106

Eh bien, quelle est la source de données? Votre action peut prendre quelques arguments par défaut, c'est-à-dire

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

par défaut dans la configuration des routes afin que startIndex soit 0 et pageSize soit (disons) 20:

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

Pour diviser le flux, vous pouvez utiliser LINQ assez facilement:

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

(ou faites une multiplication si vous utilisez "pageNumber" plutôt que "startIndex")

Avec LINQ-toSQL, EF, etc. - cela devrait également "composer" jusqu'à la base de données.

Vous devriez alors pouvoir utiliser des liens d'action vers la page suivante (etc.):

<%=Html.ActionLink("next page", "Search", new {
                query, startIndex = startIndex + pageSize, pageSize }) %>
Marc Gravell
la source
3
C'est un exemple de routage intéressant, alors je vais le voter. Je ne me suis pas encore familiarisé avec l'utilisation de LINQ, donc Skip and Take est nouveau pour moi. Mais c'est vraiment ce dont j'ai besoin. Et c'est pourquoi je marquerai ceci comme réponse.
Spoike
trucs géniaux! Merci beaucoup.
Ric Tokyo
En utilisant MVC2, votre ActionLinksyntaxe me donne une erreur de compilation lors de la demande de la page. CS0103: Le nom 'startIndex' n'existe pas dans le contexte actuel. Cette technique n'est-elle pas possible avec MVC2?
comecme
@comecme voulez-vous dire la dernière ligne? vous devez fournir ces valeurs (ou variables). Quel est cet index de démarrage / cette taille de page?
Marc Gravell
1
Ouais, je veux dire la dernière ligne. Je pensais que vous utilisiez le courant startIndexet que vous y ajoutiez pageSize. J'espérais qu'il utiliserait automatiquement les valeurs du dernier appel à Search. Comment utiliser le startIndexdu dernier Searchdans mon ActionLink?
comecme
16

J'ai eu le même problème et j'ai trouvé une solution très élégante pour une classe de téléavertisseur de

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

Dans votre contrôleur, l'appel ressemble à:

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

et à votre avis:

<div class="pager">
    Seite: <%= Html.Pager(ViewData.Model.PageSize, 
                          ViewData.Model.PageNumber,
                          ViewData.Model.TotalItemCount)%>
</div>
Oliver
la source
C'est pour ASP.NET MVC Preview 5. Cela fonctionnera-t-il pour ASP.NET MVC Beta?
Spoike
Lien changé, code mis à jour vers RC1 (je suppose que cela fonctionnera aussi avec 1.0, va essayer maintenant) blogs.taiga.nl/martijn/2008/08/27/paging-with-aspnet-mvc
Palantir
16

Je voulais également couvrir un moyen simple de le faire avec le frontal:

Manette:

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

Vue:

@* 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>
}
dav_i
la source
3
var data = this.dataSource.Skip(page * PageSize).Take(PageSize).ToList();Nécessite un orderBy(o => o.Id)avant de pouvoir utiliser skip()|| En plus de cela, c'est une excellente réponse qui mérite beaucoup plus de votes positifs.
Vahx
4

Voici un lien qui m'a aidé avec cela.

Il utilise le package NuGet PagedList.MVC. J'essaierai de résumer les étapes

  1. Installez le package NuGet PagedList.MVC

  2. Projet de construction

  3. Ajouter using PagedList; au contrôleur

  4. Modifiez votre action pour définir la page public ActionResult ListMyItems(int? page) { List list = ItemDB.GetListOfItems(); int pageSize = 3; int pageNumber = (page ?? 1); return View(list.ToPagedList(pageNumber, pageSize)); }

  5. Ajouter des liens de pagination au bas de votre vue @*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 }))

Aja Enyi
la source
1
Je sais que c'est une vieille question, c'est pourquoi cette réponse n'a pas beaucoup de votes positifs. Mais il devrait car c'est la meilleure solution moderne. Démo PagedList
omgGenerics
2

Manette

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

Vue pour afficher le nombre total de pages

 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>
        }
    }
DotNetLover
la source
2

Je pense que le moyen le plus simple de créer une pagination dans l'application ASP.NET MVC consiste à utiliser la bibliothèque PagedList.

Il existe un exemple complet dans le référentiel github suivant. J'espère que cela aiderait.

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

Lien de démonstration: http://ajaxpagination.azurewebsites.net/

Code source: https://github.com/ungleng/SimpleAjaxPagedListAndSearchMVC5

LENG UNG
la source
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=@(@[email protected])">&laquo;</a></li>
            @foreach (var item in @Model.Pages)
            {
                <li class="page-item @item.Class"><a class="page-link" href="?page=@([email protected])">@item.Page</a></li>
            }
            <li class="page-item @Model.NextClass"><a class="page-link" href="?page=@(@[email protected])">&raquo;</a></li>
        </ul>
    </div>
 </nav>

Logique de pagination

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

Utilisation du contrôleur

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);
}
Kishu
la source
Qu'est-ce que 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>
Prashant vishwakarma
la source