Thursday, September 20, 2012

MVC WebGrid Helper


If you are using Razor views and need to build a grid to show data, you can leverage the WebGrid  HTML helper. This helper can let us build a grid with several features like custom styles, sorting, paging and AJAX reload.   

This helper is found in the System.Web.Helpers.dll which should be configured automatically when using WebMatrix. If you are using Visual Studio 2010 MVC 3 projects with Razor views, you may need to install a NuGet package by entering this command in the Package Manager Console (Tools->Library Package Manager)

Install-Package RazorGenerator.Templating

That command should add the reference automatically.

The Model:

For the purpose of this article, we will be using a simple model with a few properties. 

public class Item
{     
    public int Id{get;set;}
    public string Name{get;set;}
    public string Description{get;set;}
}

We will create a list of items that we can show on the grid:

List<Models.Item> items = new List<Models.Item>();
items.Add(new Models.Item{Id=1,Name="Prod1",Description="one"});
items.Add(new Models.Item{Id=2,Name="Prod2",Description="two"});
items.Add(new Models.Item{Id=3,Name="Prod3",Description="three"});
items.Add(new Models.Item{Id=4,Name="Prod4",Description="four"});
 
Now that we have the model ready with a few records, we can work on showing the data on the grid.

Basic Grid:

To build a basic grid, we just need to instantiate the grid and pass the model in the constructor:

WebGrid grid = new WebGrid(items);

On the view, we just need to add this mark-up:

@grid.GetHtml()

We can now run the application and load the view. The grid on its simplest form looks like this:


This is just a basic HTML table with not much style, but the WebGrid helper provides several other features that can allow us to customize the way it renders. For example, if you need to control the number of pages, you can change the instantiation to look like this:

WebGrid grid = new WebGrid(items, rowsPerPage:2);

The view now renders a paging control on the footer of the grid, and it shows two records per page.


We should now control the way the columns are displayed. This can be done by adding columns to the grid to specify the columns order, the field to bind and the header label.


@grid.GetHtml(
       columns:grid.Columns(
             grid.Column("Id", "Item Id"),
             grid.Column("Name", "Name"),
             grid.Column("Description", "Description")
       )
      )

After making this change, we can now refresh the page, and the grid should look this way:



Grid and Styles:

We should now try to improve the design with some CSS changes. The WebGrid helper allows us to add a class names to style the table, header, footer, row and alternating row elements. We first add these CSS styles:

.gridTable {margin: 5px;padding: 10px;border: 1px #c8c8c8 solid;border-collapse: collapse;min-width: 550px; background-color: #fff;color: #fff;}
.gridHead th{font-weight: bold;background-color: #030D8D;color: #fff;padding: 10px}
.gridHead a:link,.gridHead a:visited,.gridHead a:active,.gridHead a:hover {color: #fff;}
.gridHead a:hover {text-decoration:underline;}
.gridTable tr.gridAltRow{background-color: #efeeef;}
.gridTable tr:hover{background-color: #f6f70a;}
.gridAltRow td{padding: 10px;margin: 5px; color: #333;}
.gridRow td{padding: 10px;color: #333;}
.gridFooter td{padding: 10px; background-color: #c7d1d6;color: #999;font-size: 12pt;text-align: center;}
.gridFooter a{font-weight: bold;color: #333; border: 1px #333 solid;}

We can now apply the styles to the grid by associating the grid elements to our CSS class names as listed below:

@grid.GetHtml(
       tableStyle: "gridTable",
       headerStyle: "gridHead",
       footerStyle:"gridFooter",
       rowStyle:"gridRow",
       alternatingRowStyle: "gridAltRow",
       columns:grid.Columns(
             grid.Column("Id", "Item Id"),
             grid.Column("Name", "Name"),
             grid.Column("Description", "Description")
       )
      )

We refresh the page, and our grid now looks like this:




That is much better. You can also notice that the paging control has been improved with better fonts and button style. We added a hover style to the rows as well. This allows us to highlight the rows as the cursor moves over them.


The grid by default provides sorting capability. If we click on the headers, we can see how the data is sorted. We added a style to the header labels to underline the selected header when the cursor hovers over the label.

AJAX Reload:

One more thing to notice is that when we sort or click to another page, the whole page refreshes.  We can prevent a page reload by using AJAX.  To achieve this, we first need to wrap the grid markup with a DIV element as follows:

<div id="gridContent">
  
    @grid.GetHtml(
       tableStyle: "gridTable",
       headerStyle: "gridHead",
       footerStyle:"gridFooter",
       rowStyle:"gridRow",
       alternatingRowStyle: "gridAltRow",
       columns:grid.Columns(
             grid.Column("Id", "Item Id"),
             grid.Column("Name", "Name"),
             grid.Column("Description", "Description")
       )
      )
 </div>

When we instantiate the grid, we need to set the AJAX parameter ajaxUpdateContainerId with the id of our div:

WebGrid grid = new WebGrid(items, rowsPerPage:2, ajaxUpdateContainerId: "gridContent");

Refresh the page, we can now try to sort or click to another page, and we can notice that there is no page post back as only the grid reloads. There are additional features that we did not cover on this post, but I hope I was able to provide a bit more insight on how to use the WebGrid helper.