Como faço a paginação no ASP.NET MVC?

85

Qual é a maneira mais preferida e fácil de fazer a paginação na ASP.NET MVC? Ou seja, qual é a maneira mais fácil de dividir uma lista em várias páginas navegáveis.

Como exemplo, digamos que recebo uma lista de elementos de um banco de dados / gateway / repositório como este:

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

    return View();
}

Para simplificar, gostaria de especificar apenas um número de página para minha ação como parâmetro. Como isso:

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

Respostas:

107

Bem, qual é a fonte de dados? Sua ação pode levar alguns argumentos padrão, ou seja,

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

padronizado na configuração de rotas para que startIndex seja 0 e pageSize seja (digamos) 20:

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

Para dividir o feed, você pode usar o LINQ com bastante facilidade:

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

(ou faça uma multiplicação se você usar "pageNumber" em vez de "startIndex")

Com LINQ-toSQL, EF, etc - isso deve "compor" o banco de dados também.

Você deve ser capaz de usar links de ação para a próxima página (etc):

<%=Html.ActionLink("next page", "Search", new {
                query, startIndex = startIndex + pageSize, pageSize }) %>
Marc Gravell
fonte
3
Esse é um exemplo de roteamento interessante, então irei votar a favor. Ainda não comecei a usar o LINQ, então Skip and Take é novo para mim. Mas isso é definitivamente o que eu preciso. E é por isso que vou marcar isso como resposta.
Spoike de
coisas incríveis! Muito obrigado de fato.
Ric Tokyo
Usando MVC2, sua ActionLinksintaxe está me dando um erro de compilação ao solicitar a página. CS0103: O nome 'startIndex' não existe no contexto atual. Esta técnica não é possível com MVC2?
comecme
@comecme você quer dizer a última linha? você precisa fornecer esses valores (ou variáveis). Qual é o índice inicial / tamanho da página?
Marc Gravell
1
Sim, quero dizer a última linha. Achei que você estivesse usando a corrente startIndexe adicionasse pageSizea ela. Eu esperava que fosse usar automaticamente os valores da última chamada para Search. Como eu usaria o startIndexfrom the last Searchno meu ActionLink?
vir
16

Eu tive o mesmo problema e encontrei uma solução muito elegante para uma classe Pager de

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

Em seu controlador, a chamada se parece com:

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

e na sua opinião:

<div class="pager">
    Seite: <%= Html.Pager(ViewData.Model.PageSize, 
                          ViewData.Model.PageNumber,
                          ViewData.Model.TotalItemCount)%>
</div>
Oliver
fonte
É para ASP.NET MVC Preview 5. Funcionará para ASP.NET MVC Beta?
Spoike de
Link alterado, código atualizado para RC1 (acho que funcionará com o 1.0 também, tente agora). blogs.taiga.nl/martijn/2008/08/27/paging-with-aspnet-mvc
Palantir
16

Eu queria abordar uma maneira simples de fazer isso com o front end também:

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

Visão:

@* 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
fonte
3
var data = this.dataSource.Skip(page * PageSize).Take(PageSize).ToList();Requer um orderBy(o => o.Id)antes de usar skip()|| Além disso, esta é uma ótima resposta que merece muito mais votos positivos.
Vahx de
4

Aqui está um link que me ajudou com isso.

Ele usa o pacote PagedList.MVC NuGet. Vou tentar resumir as etapas

  1. Instale o pacote PagedList.MVC NuGet

  2. Construir projeto

  3. Adicionar using PagedList; ao controlador

  4. Modifique sua ação para definir a 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. Adicione links de paginação na parte inferior de sua visualização @*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
fonte
1
Eu sei que esta é uma pergunta antiga e é por isso que essa resposta não tem muitos votos positivos. Mas deveria, pois esta é a melhor solução moderna. Demonstração 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);
    }

Logíca de negócios

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

Exibir para exibir a contagem 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
fonte
2

Acho que a maneira mais fácil de criar paginação no aplicativo ASP.NET MVC é usando a biblioteca PagedList.

Há um exemplo completo no seguinte repositório github. Espero que ajude.

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 de demonstração: http://ajaxpagination.azurewebsites.net/

Código-fonte: https://github.com/ungleng/SimpleAjaxPagedListAndSearchMVC5

LENG UNG
fonte
1

Entidade

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>

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

Usando o 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
fonte
O que é a 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
fonte