¿Cómo hago la paginación en ASP.NET MVC?

85

¿Cuál es la forma más preferida y más fácil de hacer la paginación en ASP.NET MVC? Es decir, cuál es la forma más sencilla de dividir una lista en varias páginas navegables.

Como ejemplo, digamos que obtengo una lista de elementos de una base de datos / puerta de enlace / repositorio como este:

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

    return View();
}

En aras de la simplicidad, me gustaría especificar solo un número de página para mi acción como parámetro. Me gusta esto:

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

Respuestas:

106

Bueno, ¿cuál es la fuente de datos? Su acción podría tomar algunos argumentos predeterminados, es decir

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

predeterminado en la configuración de rutas para que startIndex sea 0 y pageSize sea (digamos) 20:

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

Para dividir el feed, puede usar LINQ con bastante facilidad:

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

(o haz una multiplicación si usas "pageNumber" en lugar de "startIndex")

Con LINQ-toSQL, EF, etc., esto también debería "componerse" en la base de datos.

A continuación, debería poder utilizar enlaces de acción a la página siguiente (etc.):

<%=Html.ActionLink("next page", "Search", new {
                query, startIndex = startIndex + pageSize, pageSize }) %>
Marc Gravell
fuente
3
Es un ejemplo de enrutamiento interesante, así que lo votaré. Todavía no he entrado en la rutina de usar LINQ, por lo que Skip and Take es nuevo para mí. Pero eso es definitivamente lo que necesito. Y es por eso que marcaré esto como respuesta.
Spoike
cosas increíbles! Muchas gracias de hecho.
Ric Tokyo
Usando MVC2, su ActionLinksintaxis me está dando un error de compilación al solicitar la página. CS0103: El nombre 'startIndex' no existe en el contexto actual. ¿No es posible esta técnica con MVC2?
comecme
@comecme ¿te refieres a la última línea? debe proporcionar esos valores (o variables). ¿Qué es ese índice de inicio / tamaño de página?
Marc Gravell
1
Sí, me refiero a la última línea. Pensé que estás usando la corriente startIndexy la agregas pageSize. Esperaba que usara automáticamente los valores de la última llamada a Search. ¿Cómo usaría el startIndexfrom the last Searchen mi ActionLink?
comecme
16

Tuve el mismo problema y encontré una solución muy elegante para una clase de buscapersonas de

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

En su controlador, la llamada se ve así:

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

y en tu opinión:

<div class="pager">
    Seite: <%= Html.Pager(ViewData.Model.PageSize, 
                          ViewData.Model.PageNumber,
                          ViewData.Model.TotalItemCount)%>
</div>
Oliver
fuente
Es para ASP.NET MVC Preview 5. ¿Funcionará para ASP.NET MVC Beta?
Spoike
Enlace cambiado, código actualizado a RC1 (supongo que también funcionará con 1.0, lo probaré ahora). blogs.taiga.nl/martijn/2008/08/27/paging-with-aspnet-mvc
Palantir
16

También quería cubrir una forma sencilla de hacer esto con la interfaz:

Controlador:

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

Ver:

@* 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
fuente
3
var data = this.dataSource.Skip(page * PageSize).Take(PageSize).ToList();Requiere un orderBy(o => o.Id)antes de poder usar skip()|| Además de eso, esta es una gran respuesta que merece muchos más votos a favor.
Vahx
4

Aquí hay un enlace que me ayudó con esto.

Utiliza el paquete PagedList.MVC NuGet. Intentaré resumir los pasos

  1. Instale el paquete PagedList.MVC NuGet

  2. Proyecto de construcción

  3. Agregar using PagedList; al controlador

  4. Modifica tu acción para configurar la página public ActionResult ListMyItems(int? page) { List list = ItemDB.GetListOfItems(); int pageSize = 3; int pageNumber = (page ?? 1); return View(list.ToPagedList(pageNumber, pageSize)); }

  5. Agregue enlaces de paginación en la parte inferior de su vista @*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
fuente
1
Sé que esta es una pregunta antigua, por lo que esta respuesta no tiene muchos votos a favor. Pero debería, ya que esta es la mejor solución moderna. Demostración de PagedList
omgGenerics
2

Controlador

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

Lógica de negocios

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

Vista para mostrar el recuento total de páginas

 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
fuente
2

Creo que la forma más fácil de crear paginación en la aplicación ASP.NET MVC es usar la biblioteca PagedList.

Hay un ejemplo completo en el siguiente repositorio de github. Espero que te ayude.

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

Enlace de demostración: http://ajaxpagination.azurewebsites.net/

Código fuente: https://github.com/ungleng/SimpleAjaxPagedListAndSearchMVC5

LENG UNG
fuente
1

Entidad

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>

Lógica de paginación

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

Usando el controlador

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
fuente
¿Qué es la clase "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
fuente