En MVC hay un nugget para hacer paginación muy fácil de utilizar, pero para NET Core no encontré nada realmente bueno y sencillo, por lo que me puse manos a la obra y aquí os tengo mi solución. De hecho lo he probado en ASP Web Forms y en MVC y también sunciona. Y es muy fácil de usar. Pero como siempre, abierto a mejoras que se te ocurran tras leer este artículo.
Explicación
Para poder utilizar la paginación tenemos que recurir a utilizar LINQ sobre el objeto que contiene los datos. Como norma general trabajaremos con DataTable o DataView, que ambos los podemos convertir fácilmente a IQuerable, pero también podemos pasar una lista (List) de objetos (class) con los datos.
Otras dos variables que necesitamos pasar el el número de página y el tamaño de la lista devuelta.
Por último tenemos una pequeña dependencia de un archivo CSS con el estilo de la paginación generada. Pero este estilo es complemtante personalizable, y siempre puedes cambiar la función donde se crea la paginación y acomodarla más a tu página web.
Directamente el código
using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
public class PagedList : List
{
#region properties
public int CurrentPage { get; private set; }
public int TotalPages { get; private set; }
public int PageSize { get; private set; }
public int TotalCount { get; private set; }
public bool HasPrevious => CurrentPage > 1;
public bool HasNext => CurrentPage < TotalPages;
#endregion
#region constructor
public PagedList(List items, int count, int pageNumber, int pageSize)
{
TotalCount = count;
PageSize = pageSize;
CurrentPage = pageNumber;
TotalPages = (int)Math.Ceiling(count / (double)pageSize);
AddRange(items);
}
#endregion
#region Methods
public static PagedList ToPagedList(DataTable data, int pageNumber, int pageSize)
{
IQueryable source = drualcman.dataBases.AsQuerable(data);
int count = source.Count();
List items = source.Skip((pageNumber - 1) * pageSize).Take(pageSize).ToList();
return new PagedList(items, count, pageNumber, pageSize);
}
public static PagedList ToPagedList(DataView data, int pageNumber, int pageSize)
{
IQueryable source = drualcman.dataBases.AsQuerable(data.ToTable());
int count = source.Count();
List items = source.Skip((pageNumber - 1) * pageSize).Take(pageSize).ToList();
return new PagedList(items, count, pageNumber, pageSize);
}
public static PagedList ToPagedList(IQueryable source, int pageNumber, int pageSize)
{
int count = source.Count();
List items = source.Skip((pageNumber - 1) * pageSize).Take(pageSize).ToList();
return new PagedList(items, count, pageNumber, pageSize);
}
public static PagedList ToPagedList(IEnumerable source, int pageNumber, int pageSize)
{
int count = source.Count();
List items = source.Skip((pageNumber - 1) * pageSize).Take(pageSize).ToList();
return new PagedList(items, count, pageNumber, pageSize);
}
#endregion
#region HTML
public static StringBuilder PagedListPager(PagedList data)
{
return PagedListPager(data, string.Empty);
}
public static StringBuilder PagedListPager(PagedList data, string page)
{
if (!string.IsNullOrEmpty(page))
{
if (page.IndexOf("?") < 0) page += "?";
else page += "&";
}
else page = "?";
StringBuilder pagin = new StringBuilder();
pagin.Append("< div class="pagination-container">< ul class="pagination">");
int i;
if (data.CurrentPage > 5) i = data.CurrentPage - 5;
else i = 1;
int c = 0;
if (data.CurrentPage > 6)
{
pagin.Append($"< li class="PagedList-skipToFirst">< a href="{page}page=1"><<< /a>< /li>");
pagin.Append($"< li class="PagedList-skipToPrevious">< a href="{page}page={data.CurrentPage - 1}"><< /a>< /li>");
pagin.Append($"< li class="disabled PagedList-ellipses">< a>...< /a>< /li>");
}
else if (data.CurrentPage == 1) pagin.Append(string.Empty);
else pagin.Append($"< li class="PagedList-skipToNexts">< a href="{page}page={data.CurrentPage - 1}"><< /a>< /li>");
do
{
if (i <= data.TotalPages)
{
if (i == data.CurrentPage) pagin.Append($"< li class="active">< span>{i}< /span>< /li>");
else pagin.Append($"< li>< a href="{page}page={i}">{i}< /a>< /li>");
}
else c = 10;
i++;
c++;
} while (c < 10 && i <= data.TotalPages);
i = i-1;
if (data.CurrentPage < data.TotalPages - 4)
{
pagin.Append($"< li class="disabled PagedList-ellipses">< a>...< /a>< /li>");
pagin.Append($"< li class="PagedList-skipToNext">< a href="{page}page={data.CurrentPage + 1}">>< /a>< /li>");
pagin.Append($"< li class="PagedList-skipToLast">< a href="{page}page={data.TotalPages}">>>< /a>< /li>");
}
else if (data.CurrentPage == data.TotalPages) pagin.Append(string.Empty);
else pagin.Append($"< li class="PagedList-skipToNext">< a href="{page}page={data.CurrentPage + 1}">>< /a>< /li>");
pagin.Append("< /ul>< /div>");
return pagin;
}
#endregion
}
Modo de uso
Como norma general yo lo utilizo desde una clase que llamo ViewModel, pero puedes utilizarlo directamente desde el controllador y pasar como modelo la clase PagedList (ojo. la T en el model debe de ser exactamente el tipo de datos a recibir, DataRow, DataView o la class que estás utilizando en el List).
Controlador
[HttpGet]
public IActionResult Index(int page = 1)
{
DataView dv = [datos];
int pageSize = 10;
return View(PagedList.ToPagedList(dv, page, pageSize));
}
Vista
@model PagedList
@{
ViewData["Title"] = "Index";
string url = Url.Action("index", "home");
}
< div class="block-table-wp">
< div class="table-container">
< table class="table is-fullwidth border mb-0">
< thead>
< tr>
< th>Id< /th>
< /tr>
< /thead>
< tbody>
@{
if (Model.Count > 0)
{
foreach (DataRow item in Model)
{
< tr>
< td>@item["Id"]< /td>
< /tr>
}
}
else
{
< td class="text-center text-bold">No data in this table< /td>
< /tr>
}
}
< /tbody>
< tfoot>
< tr>
< td>
@Html.Raw(PagedList.PagedListPager(Model, url))
< /td>
< /tr>
< /tfoot>
< /table>
< /div>
< /div>Conclusiones
No olvidar que hay que hacer referencia al namespace donde hayais copiado la clase, tanto en el controlador como en el web.config de la web.
Happy codding
#ASP #CASHARP #CORE #MVC
|