I've been working on a project which requires server side paging and sorting to cope with potentially millions of records. I originally used the jQuery Tablesorter plugin with client side sorting and paging which worked well both functionally and aesthetically, but for the full bells and whistles project I stumbled upon the MSDN post Get the Most out of WebGrid in ASP.NET by Stuart Leeks.
Within in the midst of Stuart's post he creates a wrapper for the ASP.NET MVC WebGrid to allow Strong Typing. I debated the practicality of using strong typing with WebGrid which could be said to work better dynamically, but there are other benefits to strong typing which make this a decent little coding nugget.
Before getting to the code I'll give you a quick looky at how it works from the UI:
<div>
@{
var grid = new WebGrid<Product>(null, rowsPerPage: Model.PageSize, defaultSort: "Name");
grid.Bind(Model.Products, rowCount: Model.TotalRows, autoSortAndPage: false);
}
@grid.GetHtml(
columns: grid.Columns(
grid.Column(
"Name", format: @<text>@Html.ActionLink((string)item.Name,
"Details", "Products", new { id = item.Id }, null)</text>),
grid.Column("Description")
)
)
</div>
I created the WebGrid wrapper class in an Infrastructure folder in my website. It references another class called EnumerableExtensions which provides a useful SafeCast method to cast an IEnumerable. Here's the code:
Strongly Typed WebGrid Wrapper (WebGrid.cs)
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Helpers;
namespace MyWebSite.Infrastructure
{
/// <summary>
/// Wrapper for System.Web.Helpers.WebGrid that preserves the item type from the data source
/// </summary>
/// <typeparam name="T"></typeparam>
public class WebGrid<T> : WebGrid
{
/// <param name="source">Data source</param>
/// <param name="columnNames">Data source column names. Auto-populated by default.</param>
/// <param name="defaultSort">Default sort column.</param>
/// <param name="rowsPerPage">Number of rows per page.</param>
/// <param name="canPage">true to enable paging</param>
/// <param name="canSort">true to enable sorting</param>
/// <param name="ajaxUpdateContainerId">ID for the grid's container element. This enables AJAX support.</param>
/// <param name="ajaxUpdateCallback">Callback function for the AJAX functionality once the update is complete</param>
/// <param name="fieldNamePrefix">Prefix for query string fields to support multiple grids.</param>
/// <param name="pageFieldName">Query string field name for page number.</param>
/// <param name="selectionFieldName">Query string field name for selected row number.</param>
/// <param name="sortFieldName">Query string field name for sort column.</param>
/// <param name="sortDirectionFieldName">Query string field name for sort direction.</param>
public WebGrid(IEnumerable<T> source = null, IEnumerable<string> columnNames = null, string defaultSort = null, int rowsPerPage = 10, bool canPage = true, bool canSort = true, string ajaxUpdateContainerId = null, string ajaxUpdateCallback = null, string fieldNamePrefix = null, string pageFieldName = null, string selectionFieldName = null, string sortFieldName = null, string sortDirectionFieldName = null)
: base(source.SafeCast<object>(), columnNames, defaultSort, rowsPerPage, canPage, canSort, ajaxUpdateContainerId, ajaxUpdateCallback, fieldNamePrefix, pageFieldName, selectionFieldName, sortFieldName, sortDirectionFieldName)
{
}
public WebGridColumn Column(string columnName = null, string header = null, Func<T, object> format = null, string style = null, bool canSort = true)
{
Func<dynamic, object> wrappedFormat = null;
if (format != null)
{
wrappedFormat = o => format((T)o.Value);
}
WebGridColumn column = base.Column(columnName, header, wrappedFormat, style, canSort);
return column;
}
public WebGrid<T> Bind(IEnumerable<T> source, IEnumerable<string> columnNames = null, bool autoSortAndPage = true, int rowCount = -1)
{
base.Bind(source.SafeCast<object>(), columnNames, autoSortAndPage, rowCount);
return this;
}
}
}
Enumberable Extensions (Enumerable Extensions.cs)
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
namespace MyWebSite.Infrastructure
{
public static class EnumerableExtensions
{
public static IEnumerable<TTarget> SafeCast<TTarget>(this IEnumerable source)
{
return source == null ? null : source.Cast<TTarget>();
}
}
}
To read more about the WebGrid I suggest reading Stuart Leeks' excellent post. Additionally, learn how to Style the ASP.NET MVC WebGrid.