Grid
The Grid component allows for the easy construction of HTML tables for displaying data from a collection of Model objects.The following blog posts provide an introduction to the Grid component.
- Introduction
- Syntax
- GridModels and GridRenderers
- Limitations of the WebForms View Engine
- The ActionSyntax
- Sorting
- Auto-generated columns
Updated documentation will be available shortly
Introduction
The Grid component provides a strongly-typed way to build an HTML table using a fluent interface and lambda expressions. The Grid component is located in the MvcContrib.UI.Grid namespace and can be accessed by calling the Html.Grid extension method.Basic Syntax
To define a basic grid you'll need to call the Html.Grid extension method from within your view. There are two overloads for this method - the first takes a strongly-typed collection and the second takes a viewdata key as a string.For example, imagine that you have a controller action which passes a strongly-typed collection to the View's Model property:
...then you can pass the collection directly to the grid:
Alternatively, you might choose to use ViewData:
...in which case you can can pass the ViewData key to the Grid method. In this case, you also have to specify the type of collection in the ViewData by using a generic type parameter:
Next, you can use the Columns method to define which properties on your object should be rendered as columns in the grid. In this case, our customer object is defined as:
If we wanted to generate columns for three of these properties, the grid definition would look like this:
Note that we use a nested closure which can be used to configure the underlying ColumnBuilder.
In this case, the grid will contain a column for each of these three properties. The column heading will contain the name of the property. For PascalCased properties, the column heading will contain additional spaces (eg DateOfBirth would become "Date Of Birth")
Custom Columns
Columns can also contain arbitrary output - they do not have to be tied to a single property. For example, you could define a composite column that concatenates the Surname and Forename properties of our Customer object.Note that in this case we concatenate the Surname and Forename properties within the column expression. In this case, the Grid will not be able to infer the column heading, so it must be explicitly specified by calling the Named method.
This can also be taken a stage further. For example, we could construct some custom HTML from within this expression:
In this case, we use the standard ASP.NET MVC Html.ActionLink helper to generate a link to the "Show" action on our controller. Note the call to DoNotEncode at the end of the column definition. By default, all column output is HTML-encoded, but in this case we want to bypass the HTML encoding as we want to display custom HTML in the column.
Note The call to DoNotEncode is unnecessary using the latest source-code drop if the contents of the column column returns an instance of MvcHtmlString . However, the current release build still requires this call.
Column options
Columns can specify additional options which are configured by chaining additional methods to the end of column.For(...).Option | Description | Example |
---|---|---|
Named | Provides a custom display name for a column | column.For(x => x.Name).Named("Customer Name") |
DoNotSplit | By default, all PascalCased property names are split (so "DateOfBirth" would become "Date Of Birth"). This option disables this behavior. | column.For(x => x.DateOfBirth).DoNotSplit() |
Format | Provides a custom formatting string for a cell value | column.For(x => x.DateOfBirth).Format("{0:d}") |
CellCondition | Accepts a function that specifies whether a particular cell should be rendered | column.For(x => x.Salary).CellCondition(x => User.Identity.IsInRole("Admin")) |
Visible | Controls whether an entire column should be shown. The default is true. | column.For(x => x.Salary).Visible(User.Identity.IsInRole("Admin")) |
Encode | Controls whether the contents of a cell should be encoded. Note This option is new and is not contained in the current release - use "DoNotEncode" instead. | column.For(x => x.SomeProperty).Encode(false) |
HeaderAttributes | Provides additional custom attributes for the column header. This can be provided either as a dictionary or by using a Hash | column.For(x => x.Surname).HeaderAttributes(new Dictionary<string, object> { { "class", "foo" } }) OR column.For(x => x.Surname).HeaderAttributes(@class => "foo") |
Attributes | Provides custom attributes for a cell. This can be provided either as a dictionary or by using a Hash | column.For(x => x.Surname).Attributes(x => new Dictionary<string, object> { { "class", "foo" } }) OR column.For(x => x.Surname).Attributes(@class => "foo") |
Sortable | Specifies whether a column is sortable. This only applies if sorting is enabled (see below). The default is true | column.For(x => x.Id).Sortable(false) |
SortColumnName | Specifies a custom column name for use with sorting (see below) | column.For(x => x.Surname).SortColumnName("CustomerName") |
InsertAt | Specifies the order of the column when overriding auto-generated columns (see below). This option is new and is not included in the latest release. | column.For(x => x.Surname).InsertAt(0) |
Automatically generated columns
If you are using a dedicated presentation model with your view, then the AutoGenerateColumns method can be used to automatically generate a column for each public property on your model rather than having to explicitly specify each column.Under the covers, the AutoGenerateColumns method uses the MVC2 ModelMetadata provider to work out how the properties should be rendered. As such, the DataAnnotations attributes can be used to customise how auto-generated columns should be rendered. At present, the following attributes are supported:
- ScaffoldColumn - can be used to hide a particular column (equivalent of column.Visible(false))
- DisplayName - can be used to provide a custom column name (equivalent of column.Named("foo"))
- DisplayFormat - can be used to provide a custom format for a column (equivalent of column.Format("{0:some format}"))
You can add additional columns after the automatically generated columns by calling the Columns method:
You can also re-arrange the additional columns. For example, if you wanted your extra column to appear before the auto-generated columns then you can use the InsertAt method to specify an index. Note This is a new feature that is not in the latest release, so if you want to make use of this then you will need to either build from source or download a nightly build.
Sorting
Unlike the ASP.NET Web Forms GridView control, the MvcContrib grid does not perform any sorting of your data itself. However, it can be used to render data that has been sorted in your controller action (or a service layer).To enable sorting, you first need to take a GridSortOptions object in your controller action:
This object contains two properties (Column and Direction) that can be used to sort your data. MvcContrib contains an additional overload for Linq's OrderBy method which accepts a column name and a sort direction, but use of this method is optional - you can use whatever mechanism you like for performing the sort.
The GridSortOptions instance will then need to be passed to the view in order to tell the grid how the data has been sorted.
In the view, the Sort method should be called on the grid. This method accepts an instance of GridSortOptions so that the grid knows how the data has been sorted and can therefore work out how the sorting links in the column headers should be generated.
At this point, the Grid will now add hyperlinks in the column headings. The hyperlink will contain two querystring parameters - Column and Direction. These will be used by the MVC Model-binding infrastructure in order to create the GridSortOptions object that is passed to the controller action.
When the data has been sorted on a column, the grid will place additional CSS classes in the column headings. If the column is currently sorted in ascending order then the appropriate <th> tag will have a class of sort_asc. Likewise, if the column is sorted in descending order then the css class will be sort_desc. These classes can be used to add additional styling (for example, to add up/down arrows). Please look at the MvcContrib.Examples.UI project for a complete example.
Paging
Similar to the sorting example, the grid does not actually perform any paging internally but it can be used to render pre-paged data. To enable this, you'll need to take an additional argument for your controller action called "page":This argument will be used to specify which page of data should be rendered. As with the sorting example, you are free to use whatever mechanism you wish to perform the paging, but MvcContrib does provide an extension method on IEnumerable called AsPagination*. The only requirement is that the result of performing the paging returns an implementation of the IPagination interface.
In this example, we pass the page number to the AsPagination method (defaulting to page 1 if no page was specified in the querystring) with a page size of 10.
The grid requires no modifications in order for this to work - the IPagination interface also implements IEnumerable, so the grid can process this as with any other collection.
However, in order to render paging links on the page, you can make use of the Html.Pager extension method which is in the MvcContrib.UI.Paging namespace:
TODO: Write documentation on the additional options available on the Pager.