Use MvcContrib Grid to Display a Grid of Data in ASP.NET MVCBy Scott Mitchell
The past six articles in this series have looked at how to display a grid of data in an ASP.NET MVC application and how to implement features like sorting, paging, and filtering. In each of these past six tutorials we were responsible for generating the rendered markup for the grid. Our Views included the
<th>elements for the header row, and a
foreachloop that emitted a series of
<td>elements for each row to display in the grid. While this approach certainly works, it does lead to a bit of repetition and inflates the size of our Views.
The ASP.NET MVC framework includes an
HtmlHelper class that adds support
for rendering HTML elements in a View. An instance of this class is available through the
Html object, and is often used in a View to create action links
Html.ActionLink), textboxes (
Html.TextBoxFor), and other HTML content. Such content could certainly be created by writing the markup by hand
in the View; however, the
HtmlHelper makes things easier by offering methods that emit common markup patterns. You can even
create your own custom HTML Helpers by adding
extension methods to the
MvcContrib is a popular, open source project that adds various functionality to the ASP.NET MVC framework. This includes
a very versatile Grid HTML Helper that provides a strongly-typed way to construct a grid in your
Views. Using MvcContrib's Grid HTML Helper you can ditch the
<td> markup, and instead use
Html.Grid(...). This article looks at using the MvcContrib Grid to display a grid of data in an ASP.NET MVC application. A future installment
will show how to configure the MvcContrib Grid to support both sorting and paging. Read on to learn more!
Step 0: A Brief Roadmap
This article walks through rendering a grid of data in an ASP.NET MVC application using the MvcContrib Grid HTML Helper. It is presumed that you have already read and worked through the previous articles in this series as we will rely on code created in earlier tutorials. The aim of this tutorial is to familiarize ourselves with the MvcContrib Grid and to end up with an ASP.NET MVC View that displays the name, category, quantity per unit, price, and discontinued status of all of the products in the Northwind database in a non-sortable, non-paged grid. (Future installments will look at implementing sorting and paging with MvcContrib Grid.)
As the screen shot below shows, the grid we will create in this article is identical to the one that we created in the first installment in this series, Displaying a Grid of Data in ASP.NET MVC. While the output is same, the syntax used in the View is quite different, as we will see shortly.
Step 1: Downloading and Referencing the MvcContrib Project
To follow along with the code presented in this article you'll need to download the MvcContrib project and reference it from your ASP.NET MVC application. You can get your hands on the MvcContrib assembly (the DLL file) by either downloading the demo available at the end of this project or by going to the MvcContrib Releases page. In either event, the file you need to add to your project is
- From the MvcContrib Releases page, download the
MvcContrib.dllis one of the files in the root of the ZIP.
- From the demo available for download from this article, you'll find
Binfolder. Note that the demo in this article uses MvcContrib version 18.104.22.168, which was released on January 16th, 2011. A more recent version may be available.
MvcContrib.dllfile, the next step is to add a reference to it from your project. From Visual Studio's Solution Explorer, right-click on the References folder and choose Add Reference. This launches the Add Reference dialog box. From there, click the Browse button, locate the
MvcContrib.dllfile, and click the Add button.
Step 2: Creating a New Controller and a Base Controller Class
All of the demos for the past six articles used the same Controller,
ProductsController. I decided to create a new Controller for the MvcContrib Grid demos named
ProductsMvcContribController. If you are following along at your computer, right-click on the
Controllersfolder and choose the Add --> Controller menu option, naming the new Controller
Recall that the
ProductsController has a protected property named
DataContext that returns an instance of the
NorthwindDataContext class is one of the classes auto-generated by the Linq-to-SQL library, which is what these demos use to access the database.)
Because we need to access the database in the new Controller you may be tempted to copy and paste the
DataContext property from the
class into the new
ProductsMvcContribController class. But anytime you find yourself copying and pasting code you should stop and pause because it likely means
you're doing something wrong. In this case, it's an indication that we're violating the DRY principle -
Don't Repeat Yourself! A better approach is to create a base
Controller class that defines the
DataContext property and
then have those Controllers that need to access the database derv ice from this base class.
Add a new class file to the
Controllers folder named
BaseController. Have this class derive from the
and then move the
DataContext property from the
ProductsController class to this new base class. After these changes your
class should look similar to the following. (Note: You will need to include a
using statement to the
System.Data.Linq namespaces; if you run into problems or want to see the full code you can always download the complete working demo available at the end of this article.)
Next, have all of the Controllers in the application extend the
BaseController class. For instance, the new
class would look like so:
Step 3: Implementing the
The purpose of a Controller action is two-fold: to create the Model and determine what View to use to render the output. The current
return View()statement in the
Indexaction handles the latter part - selecting the View - but we've yet to specify the Model. Because we want the View to display information about all products we can have the Model simply be the set of
Productobjects in the database. This information can be retrieved using
this.DataContext.Productsand sent to a strongly-typed View by passing the Model into the
return View()statement like so:
In this case the Model is quite simple - just the set of products to display. As we saw in previous tutorials, this Model gets a bit more interesting when rendering a grid that supports sorting, paging, or filtering. For now, we'll stick with our simplistic Model, but in future installments we'll have to include a bit more information in our Model to get these additional features to work.
Step 4: Creating the View
To create a View for the
Indexaction, right-click on the method name and choose the Add View menu option. This will bring up the dialog box shown below. Leave the View Name as Index, but check the "Create a strongly-typed view" checkbox and choose the
Web.Models.Productclass from the drop-down. Check the "Select master page" checkbox if it is not already checked and use the
~/Views/Shared/Site.Masterfile as the master page.
Index.aspxfile within your
Viewsfolder. Take a moment to inspect the View's
@Pagedirective at the top. The
Inheritsattribute should specify the View's strongly-typed Model as
Web.Models.Product. Because the
DataContext.Productsproperty returns a collection of
Productobjects we need to change this to an enumeration of
Web.Models.Productobjects. Modify the
@Pagedirective so that it looks like the following:
At this point we're ready to construct the markup to be returned by the View. In Displaying a Grid of Data
in ASP.NET MVC we did so by typing in the markup for a table, namely the
<table> tag and a row of
<th> tags for the header row,
followed by a
foreach loop that emitted a table row with
<td> elements for each of the columns. However, in this article we're going to
have this markup emitted for us by the MvcContrib Grid.
The MvcContrib Grid is implemented as an HTML Helper method, meaning you'll generate a grid from the View using the syntax:
Html.Grid method returns a string of HTML, which is why we use the
<%: ... %> syntax, which emits the string to the response stream.
The data to display in the grid is passed into the
Grid method. The
Columns method defines the columns to render for the grid.
Let's look at a simple example. In our View the
Model property is the enumeration of
Product objects to display in the grid, so this is what
we pass into the
Grid method. The
Columns method defines those columns to appear in the grid.
The syntax used for the
Column method may seem a bit intimidating at first. The grid is interested in working with a collection of
Columns method is what constructs this collection. It is passed in a lambda expression that builds the columns using a
fluent syntax. In short, each
col.For(...) statement adds a
GridColumn object to
the collection of columns for a particular field in the data being displayed. In our example, the first column displays the value of the
ProductName property, whereas the second displays the
With this HTML Helper syntax in place, visit the page through a browser. As the screen shot below shows, we get a functional grid.
Keep in mind that this grid was rendered without us having to write a lick of markup - no
<table> tags, no
<tr> tags, etc.
Instead, we just called the
Html.Grid method, passed it the data to display and information on what columns to display, and it did the rest.
("The rest," in this case, involves enumerating the data (the list of products) and generating the markup to display a grid in the browser.)
Step 5: Customizing the MvcContrib Grid's Columns
The display of the MvcContrib Grid requires a bit more work in order to get it to look like the grid from the first article in this series. In particular, we need to:
- Rename the first four header columns to Product, Category, Qty/Unit, and Price.
- Format the
UnitPricevalue as a currency.
- Have the first four columns' texts left-aliged.
- Display the red X icon for discontinued items (rather than True/False).
col.For(...)method calls. You can make additional method calls for a particular column to specify formatting and display-related settings. These just get tacked on after the
Formethod call. For example, to specify a different name for the column's header cell use the
Namedmethod like so:
To format a cell use the
Format(formatSpecifier) method. To format the
UnitPrice value as a currency we'd use:
Note how the
Format method just gets tacked onto the end of the previous method (
Named). You can string together any number of the column-related
methods in this manner.
Another such method is
Attributes, which applies an HTML attribute to the cells in the column. By default, the CSS rules in the demo application center
the text in each table cell. There are CSS classes that specify an alternative justification. We can apply these classes to a column using the
method with the following syntax:
The above syntax applies the "left" CSS class to the first three columns and the "right" CSS class to the four column, Price. Note that when specifying the class attribute name
we need to preface the name "class" with an at sign (
@). This is because the word
class is a reserved word in C#; without the
C# will report a compile-time error.
The final formatting-related task is to replace the Discontinued column's True/False output with an image for discontinued items and an empty string for non-discontinued
items. This can be accomplished using C#'s ternary operator to output different markup depending on
Discontinued property value.
The following syntax starts by evaluating the expression on the left,
p.Discontinued. If it evaluates to True - that is, if
true - then the value after the question mark (
?) is emitted -
<img src="Content/cancel.png" />. If the expression
evaluates to False - that is, if
false - then the value after the colon (
:) is emitted -
This has the effect of rendering an
<img> element that displays the red X for discontinued products while showing an empty cell for non-discontinued
In addition to using the ternary statement in the
For method we also need to use the
Encode method, specifying that MvcContrib Grid should
not HTML encode this cell's output. (If you omit the
Encode(false) method call then the
<img> element markup will be encoded,
displaying the literal text
<img src="Content/cancel.png" /> in the cell.) Also, by using a custom statement in the
MvcContrib Grid cannot auto-determine the header column name, so we need to provide it via the
With these modifications in place we have arrived at a grid that looks identical to the one from the first article in this series. MvcContrib Grid has allowed us to
construct such a grid without having to write a line of table markup. Instead, this markup is entirely generated by the
Grid HTML Helper method.
MvcContrib Grid provides a markup-free way of displaying a grid of data in an ASP.NET MVC application. While there is a bit of a learning curve with MvcContrib Grid, once you familiarize yourself with the syntax I wager you'll find it an efficient tool for displaying grids. Another benefit of the MvcContrib Grid is that it has baked in support for paging and supporting. In the next article in this series we'll see how to enable this functionality.
Until then... Happy Programming!