Last active
December 11, 2017 13:10
-
-
Save odytrice/5698688 to your computer and use it in GitHub Desktop.
ASP.NET MVC Paging Class
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Collections.Generic; | |
using System.Linq; | |
using System.Text; | |
using System.Web; | |
using System.Web.Mvc; | |
using System.Web.Routing; | |
namespace System.Web.Mvc | |
{ | |
#region PagedList Interface | |
public interface IPagedList | |
{ | |
int PageCount { get; } | |
int TotalCount { get; } | |
int PageSize { get; } | |
bool HasPreviousPage { get; } | |
bool HasNextPage { get; } | |
bool IsFirstPage { get; } | |
bool IsLastPage { get; } | |
int ItemStart { get; } | |
int ItemEnd { get; } | |
int PageNumber { get; } | |
} | |
public interface IPagedList<T> : IPagedList, IList<T> { } | |
#endregion | |
#region PagedList Implementation | |
public class PagedList<T> : List<T>, IPagedList<T> | |
{ | |
//Properties | |
public int PageCount { get; private set; } | |
public int TotalCount { get; private set; } | |
public int PageSize { get; private set; } | |
public bool HasPreviousPage { get; private set; } | |
public bool HasNextPage { get; private set; } | |
public bool IsFirstPage { get; private set; } | |
public bool IsLastPage { get; private set; } | |
public int ItemStart { get; private set; } | |
public int ItemEnd { get; private set; } | |
public int PageNumber { get { return PageIndex + 1; } } | |
public int PageIndex { get; private set; } | |
//Constructors | |
public PagedList(IEnumerable<T> source, int pageNumber, int pageSize) | |
: this(source.AsQueryable(), pageNumber, pageSize) | |
{ | |
} | |
public PagedList(IQueryable<T> source, int pageNumber, int pageSize) | |
{ | |
//Error Checking | |
if (pageSize < 1) | |
throw new ArgumentOutOfRangeException("pageSize", "Value can not be less than 1"); | |
if (source == null) | |
source = new List<T>().AsQueryable(); | |
if (pageNumber < 1) pageNumber = 1; | |
//Paging Info | |
PageSize = pageSize; | |
PageIndex = pageNumber - 1; | |
TotalCount = source.Count(); | |
PageCount = TotalCount > 0 ? (int)Math.Ceiling(TotalCount / (double)pageSize) : 0; | |
//Navigation Info | |
HasPreviousPage = PageIndex > 0; | |
HasNextPage = PageIndex < PageCount - 1; | |
IsFirstPage = PageIndex <= 0; | |
IsLastPage = PageIndex >= PageCount - 1; | |
ItemStart = PageIndex * PageSize + 1; | |
ItemEnd = Math.Min(PageIndex * PageSize + PageSize, TotalCount); | |
//If Source is Empty | |
if (TotalCount <= 0) | |
return; | |
int totalPages = (int)Math.Ceiling(TotalCount / (double)PageSize); | |
if (PageIndex >= totalPages) | |
AddRange(source.Skip((totalPages - 1) * PageSize).Take(PageSize)); | |
else | |
AddRange(source.Skip(PageIndex * PageSize).Take(PageSize)); | |
} | |
} | |
#endregion | |
#region Page Link Construction | |
public class Pager : IHtmlString | |
{ | |
private readonly HtmlHelper _htmlHelper; | |
private readonly int _pageSize; | |
private readonly int _currentPage; | |
private readonly int _totalItemCount; | |
private readonly string _routeKey; | |
public Pager(HtmlHelper htmlHelper, int pageSize, int currentPage, int totalItemCount, string routeKey) | |
{ | |
_htmlHelper = htmlHelper; | |
_pageSize = pageSize; | |
_currentPage = currentPage; | |
_totalItemCount = totalItemCount; | |
_routeKey = routeKey; | |
} | |
public IEnumerable<PaginationLink> BuildPaginationModel(Func<int, string, string> generateUrl) | |
{ | |
var model = new List<PaginationLink>(); | |
var pageCount = (int)Math.Ceiling(_totalItemCount / (double)_pageSize); | |
// Create Previous Link | |
model.Add(_currentPage > 1 ? new PaginationLink | |
{ | |
Active = true, | |
DisplayText = "«", | |
PageIndex = _currentPage - 1, | |
Url = generateUrl(_currentPage - 1, _routeKey) | |
} : new PaginationLink | |
{ | |
Active = false, | |
DisplayText = "«" | |
}); | |
//Numbered Page Links 1,2,3.. | |
for (var i = 1; i <= pageCount; i++) | |
{ | |
if (i == _currentPage || (_currentPage <= 0 && i == 0)) | |
{ | |
model.Add(new PaginationLink { Active = true, PageIndex = i, IsCurrent = true, DisplayText = i.ToString() }); | |
} | |
else | |
{ | |
model.Add(new PaginationLink { Active = true, PageIndex = i, DisplayText = i.ToString(), Url = generateUrl(i, _routeKey) }); | |
} | |
} | |
// Next | |
model.Add(_currentPage < pageCount ? new PaginationLink | |
{ | |
Active = true, | |
PageIndex = _currentPage + 1, | |
DisplayText = "»", | |
Url = generateUrl(_currentPage + 1, _routeKey) | |
} : new PaginationLink | |
{ | |
Active = false, | |
DisplayText = "»" | |
}); | |
return model; | |
} | |
public string ToHtmlString() | |
{ | |
//Hide Navigation if elements are less than a page | |
if (_totalItemCount <= _pageSize) | |
{ | |
return ""; | |
} | |
//Build Pager | |
IEnumerable<PaginationLink> model = BuildPaginationModel(GeneratePageUrl); | |
StringBuilder listItems = new StringBuilder(); | |
foreach (var paginationLink in model) | |
{ | |
if (paginationLink.Active) | |
{ | |
if (paginationLink.IsCurrent) | |
{ | |
listItems.AppendFormat("<li class='active'><a>{1}</a></li>", paginationLink.Url, paginationLink.DisplayText); | |
} | |
else if (!paginationLink.PageIndex.HasValue) | |
{ | |
listItems.AppendFormat("<li><a href='{0}'>{1}</a></li>", paginationLink.Url, paginationLink.DisplayText); | |
} | |
else | |
{ | |
listItems.AppendFormat("<li><a href='{0}'>{1}</a></li>", paginationLink.Url, paginationLink.DisplayText); | |
} | |
} | |
else | |
{ | |
listItems.AppendFormat("<li class='disabled'><a>{1}</a></li>", paginationLink.Url, paginationLink.DisplayText); | |
} | |
} | |
return string.Format("<ul class='pagination'>{0}</ul>", listItems.ToString()); | |
} | |
private string GeneratePageUrl(int pageNumber, string routeKey) | |
{ | |
var viewContext = _htmlHelper.ViewContext; | |
var routeData = new RouteValueDictionary(viewContext.RequestContext.RouteData.Values); | |
foreach (string key in viewContext.HttpContext.Request.QueryString.Keys) | |
{ | |
routeData.Add(key, viewContext.HttpContext.Request.QueryString[key]); | |
} | |
routeData.Remove(routeKey); | |
if (pageNumber > 1) | |
{ | |
routeData.Add(routeKey, pageNumber); | |
} | |
// 'Render' virtual path. | |
VirtualPathData virtualPathForArea = RouteTable.Routes.GetVirtualPathForArea(viewContext.RequestContext, routeData); | |
return virtualPathForArea != null ? virtualPathForArea.VirtualPath : null; | |
} | |
public class PaginationLink | |
{ | |
public bool Active { get; set; } | |
public bool IsCurrent { get; set; } | |
public int? PageIndex { get; set; } | |
public string DisplayText { get; set; } | |
public string Url { get; set; } | |
} | |
} | |
#endregion | |
#region Paging Extensions | |
public static class PagingExtensions | |
{ | |
//IQueryable and IEnumerable Extensions | |
public static IPagedList<T> ToPagedList<T>(this IQueryable<T> source, int pageNumber, int pageSize) | |
{ | |
return new PagedList<T>(source, pageNumber, pageSize); | |
} | |
public static IPagedList<T> ToPagedList<T>(this IEnumerable<T> source, int pageNumber, int pageSize) | |
{ | |
return new PagedList<T>(source, pageNumber, pageSize); | |
} | |
//Html Helper Extension | |
public static IHtmlString Pager(this HtmlHelper htmlHelper, IPagedList list, string routeKey = "page") | |
{ | |
return new Pager(htmlHelper, list.PageSize, list.PageNumber, list.TotalCount, routeKey); | |
} | |
public static IPagedList<T> Paging<T>(this HtmlHelper htmlHelper, IEnumerable<T> source, int pagelimit = 30, string pagekey = "page") | |
{ | |
int pageNumber = 1; | |
HttpRequestBase request = htmlHelper.ViewContext.HttpContext.Request; | |
if (request.QueryString[pagekey] != null) | |
{ | |
int.TryParse(request.QueryString[pagekey], out pageNumber); | |
} | |
return source.ToPagedList(pageNumber, pagelimit); | |
} | |
} | |
#endregion | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment