I am in the process of creating a site that needs to show a basic grid of data to a user, allow the user to select certain rows and then post the IDs of those rows to a web service. It is a fairly straight forward UI.
When presenting a user with a grid there are always at least two basic requirements to a good grid UI. The first requirement is sorting and the second one that I am going to examine farther into is paging. Before starting this project I had come across two projects that integrate well with MVC and implement paging:
The MVC Contrib project is great and has added a lot of useful functionality to ASP.NET MVC projects. However the paging presentation that they implement wasn’t quite what I wanted.
I really liked John’s idea and how his pager method presented the links. So I took his method and used it in my project. Thanks John! But, lately I have been on a replace all for loops with linq kick. And I thought I could enhance John’s method further with linq. The result is the code you see at the bottom of the page.
To explain what is going on in the method below, the first step in the method is to collect the controller, action name and route values, these are all things that are needed for constructing action links. Part of collecting the route values is to make sure that we have the appropriate route value for the url parameter that holds the current page. The next step was to create a range list from the first page to the last page and filter the list down to just the pages we wanted to present. Then the last step is simply just building the html string to return to the MVC view.
Enjoy!
public static class ExtensionMethods
{
/// <summary>
/// Creates paginated links
/// </summary>
/// <param name="helper">HtmlHelper class that can provide access to helpful functionality</param>
/// <param name="startPage">Starting page (most likely 1)</param>
/// <param name="currentPage">Number of the current page</param>
/// <param name="totalPages">Number of total pages</param>
/// <param name="pagesToShow">Number of pages to show forward and backward</param>
/// <param name="currentPageUrlParameter">URL Parameter that sets the current page</param>
public static MvcHtmlString Pager(this HtmlHelper helper, int startPage, int currentPage, int totalPages, int pagesToShow, string currentPageUrlParameter)
{
System.Web.Routing.RouteData routeData = helper.ViewContext.RouteData;
string actionName = routeData.GetRequiredString("action");
string controller = routeData.GetRequiredString("controller");
System.Web.Routing.RouteValueDictionary values = routeData.Values;
if (!values.ContainsKey(currentPageUrlParameter))
values.Add(currentPageUrlParameter, currentPage);
bool started = false;
StringBuilder html =
Enumerable.Range(startPage, totalPages) /* Create a list from the first page to the last page */
.Where(i => (currentPage - pagesToShow) < i & i < (currentPage + pagesToShow)) /* filter the list to just the pages we want to show */
.Aggregate(new StringBuilder(@"<div class=""pager"">"), (seed, page) =>
{
/* run through the list of pages and create the string of page numbers */
values["page"] = page;
string style = "pagerPage";
if (page == startPage)
style += " firstPage";
if (page == totalPages)
style += " lastPage";
var htmlDic = new Dictionary<string, object>();
htmlDic.Add("style", style);
if (started)
seed.Append(" | ");
else
started = true;
if (page == currentPage)
seed.AppendFormat("<span style=\"pagerPage currentPage\">{0}</span>", page);
else
seed.Append(helper.ActionLink(page.ToString(), actionName, controller, values, htmlDic).ToHtmlString());
return seed;
});
html.Append(@"</div>");
return MvcHtmlString.Create(html.ToString());
}
}
41.883991
-87.632409