Skip to content

Instantly share code, notes, and snippets.

@odytrice
Last active December 11, 2017 13:10
Show Gist options
  • Save odytrice/5698688 to your computer and use it in GitHub Desktop.
Save odytrice/5698688 to your computer and use it in GitHub Desktop.
ASP.NET MVC Paging Class
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