Legacy Grid

The Legacy Grid is the original implementation of the MvcContrib Grid. This has now been deprecated but will continue to remain as part of the project for the time being in order to provide backwards compatibility. We recommend that you migrate your code to use the new version of the grid.

Setup

In order to use the Grid, you will need to add a namespace import for MvcContrib.UI.LegacyGrid to your web.config file:

<pages>
	<namespaces>
		<add namespace="System.Web.Mvc"/>
		<add namespace="MvcContrib.UI.LegacyGrid"/>
		<add namespace="MvcContrib"/>
	</namespaces>
</pages>

Using the Grid

The grid can make use of any IEnumerable<T> that is placed in your ViewData. For example, you may have a PeopleController that returns a list Person objects from a PersonRepository:

public class PeopleController : Controller 
{
	private PersonRepository repository = new PersonRepository();
	
	public ActionResult List() 
	{
		ViewData["people"] = repository.FindAll();
		return View();
	} 
}


In your View you can then make a call to Html.Grid passing the viewdata key ("people") as the first parameter:

<%
Html.Grid<Person>(
	"people",
	column => {
		column.For(p => p.Id);
		column.For(p => p.Name);
		column.For(p => p.Gender);
		column.For(p => p.RoleId);
	}
);
%>


This will generate an HTML table with a CSS class of grid with four columns. The column headings will be generated as Id, Name, Gender and Role Id. PascalCased properties have spaces automatically inserted so RoleId becomes Role Id.

Note that if you are using strongly typed ViewData, instead of passing a string as the first argument you can pass an IEnumerable<T> directly.

Column.For

The second parameter to Html.Grid takes a delegate used to construct the column model for the grid. As this requires the use of a multi-line lambda this will not work in VB, as VB 9 does not currently support anonymous methods.

There are three overloads for column.For:
  • column.For(p => p.Id);
  • column.For(p => p.Id, "Identifier");
  • column.For("Identifier");

The first overload takes a lambda expression which is used to specify the property for which the column should be generated. The name of the property is also used for the column heading.

The second overload is similar to the first, except the column heading is explicitly specified.

The third overload is used to generate a custom column (see the section on Custom Columns and Headings).

Column Options

Grid columns have several options that can be applied to them:

Formatted

A grid column can have a string format automatically applied to it:

column.For(p => p.DateOfBirth).Formatted("{0:d}");


All standard .NET string formats are supported.

DoNotEncode

For security, all output generated by column.For(<lambda>) is HTML encoded. If you wish to disable the HTML encoding for a particular column, call the DoNotEncode method:

column.For(p => p.SomePropertyThatContainsHtml).DoNotEncode();

ColumnCondition

The ColumnCondition method takes a lambda expression that returns a boolean and can be used to prevent an entire column from being rendered if the lambda returns false:

column.For(p => p.Salary).ColumnCondition(() => (bool)ViewData["canViewSalary"]);


In this example, the Salary column will be completely hidden unless a boolean value called "canViewSalary" exists in the ViewData and is true.

CellCondition

CellCondition is similar to ColumnCondition, but is invoked once per cell rather than for the entire column. This means you can selectively hide particular cells in a column:

column.For(p => p.Salary).CellCondition(p => !p.IsAdministrator);


In this example, the Salary for administrators will not be displayed.

DoNotSplit

Unless a column heading is explicitly specified, the name of the property will be used as the column heading. If the property is PascalCased (eg DateOfBirth) then the column heading will have spaces inserted ("Date Of Birth"). If you do not want this behaviour to occur, call the DoNotSplit method and the heading would be generated as "DateOfBirth":

column.For(p => p.DateOfBirth).DoNotSplit();

Chaining

Note that all of the column options can be chained together:

column.For(p => p.DateOfBirth).Formatted("{0:d}").DoNotSplit().CellCondition(p => !p.IsAdministrator);

Custom Columns and Headings

You can add custom columns by calling column.For("column name") an then specifying a lambda for generating the HTML:

<%
Html.Grid<Person>(
	"people",
	column => {
		column.For(p => p.Id);
		column.For(p => p.Name);
		column.For(p => p.Gender);
		column.For(p => p.RoleId);
		column.For("Edit").Do(p => { %>
			<td>
				<a href="/People/Edit/<%= p.Id %>">Edit</a>
			</td>
		%>});
	}
);
%>


Although column headings can be customised by passing a string to column.For as its second parameter (eg column.For(p => p.Id, "Identifier")), sometimes it may be necessary to add additional markup into the column heading. This can be achieved by calling the Heading method on a column:

<%
Html.Grid<Person>(
	"people",
	column => {
		column.For(p => p.Id).Heading(() => { %>
			<th>My Custom Header</th>
		%>});
		column.For(p => p.Name);
		column.For(p => p.Gender);
		column.For(p => p.RoleId);
	}
);
%>


Customising the start and end of each row is also supported with the RowStart and RowEnd methods. These methods are available through an additional overload for specifiying grid sections.

<%
Html.Grid<Person>(
	"people",
	column => {
		column.For(p => p.Id);
		column.For(p => p.Name);
		column.For(p => p.Gender);
		column.For(p => p.RoleId);
	}, 
	sections => {
		sections.RowStart(p => { %>
			<tr class="myRowClass">
		%>});
	}

);
%>

Grid Options

An optional parameter containing a dictionary of options can be passed to the grid. This can be used to specify the text to display if the grid is empty, as well as any additional HTML attributes for the table. Typically, this can be done using the Hash object, although any IDictionary will work.

Options currently supported:
  • empty - Text to be displayed if the grid has no data.
  • everything else will be turned into HTML attributes on the table.

<%
Html.Grid<Person>(
	"people",
	new Hash(empty => "There are no people", style => "width: 100%"),
	column => {
		...
	}
);
%>

Paging Support

Paging is supported through the IPagination interface. In order to make use of this, you will need to import the MvcContrib.Pagination namespace in your controller and make use of the AsPagination extension method:

using MvcContrib.Pagination;

public class PeopleController : Controller 
{
	private PersonRepository repository = new PersonRepository();
	
	public ActionResult List(int? page) 
	{
		ViewData["people"] = repository.FindAll().AsPagination(page ?? 1);
		return View();
	} 
}


The AsPagination extension method will work on any IEnumerable<T> or IQueryable<T>. The argument specified is the page to return. A second, optional parameter is the size of each page. The default value is 20.

In the above example, the page is passed in via the query string. The null coalescing operator (??) is used here to default the page number to page 1 if no page has been specified (ie the page variable is null).

The grid will now automatically have paging links. No changes to the markup are required.

Advanced Column Rendering

Earlier it was shown how a custom column can be specified by calling column.For("column name"). For example:

column.For("Edit").Do(p => { %>
			<td>
				<a href="/People/Edit/<%= p.Id %>">Edit</a>
			</td>
		%>});


As an alternative to this, you can make use of lambda expressions and the ASP.NET MVC helper methods. Note that if you use this approach, you have to explicitly specify the column name as it cannot be inferred. A call to DoNotEncode is also necessary if you are going to use this approach to output HTML:

column.For(p => Html.ActionLink("Edit", "Edit", new RouteValueDictionary(new { id = p.Id })), "Edit").DoNotEncode();

Last edited Mar 4, 2009 at 1:12 PM by JeremyS, version 1

Comments

jpatevans4651 Jun 26, 2009 at 9:31 PM 
Where is the .Heading at? I'm looking to put some buttons above one of my columns and wondering if that will help. I haven't been able to figure out how to increase the header height so I can include buttons to move rows up and down for that column. If anyone has any other ideas I'm listening.