In my last post, I created a partial view page that rendered a collapsible gridview (which I now call a GridTreeView) using the MVCContrib Grid HtmlHelper extension and the jQuery ActsAsTreeTable plug-in. While the code works, there are a few drawbacks. First, I completely forgot about having to link the CSS file in to the view. That’s doable using the view codebehind, but I don’t like codebehinds in MVC. The second drawback is that it doesn’t follow the "standard" method of rendering controls in ASP.NET MVC. All the built-in controls are available via the HtmlHelper object, and that’s how I’d like to expose the GridTreeView as well. Fortunately, it isn’t too terribly difficult to do!
First, let’s define the HtmlHelper extension method (the final version of this, which I will eventually post online, includes various overloaded versions of the method):
Let’s talk through the parameters real quick, because some of them are fairly nasty.
- helper – By prefixing it with the "this" keyword, this method becomes an extension method for HtmlHelper instances, which is what we want.
- gridId – This will be used as the "id" attribute for the table that’s created by the control.
- dataSource – This is any enumerable type. Items from this data source will be used to build the rows of the grid.
- columns – Ok, this one is complicated. It is an Action delegate that takes an IRootGridColumnBuilder. What that means is that the caller must specify a delegate (or lambda) that uses an IRootGridColumnBuilder to define the columns for the grid. This is straight out of the Grid helper from MVCContrib, so go here if you want more info.
- idSelector – This is a delegate (or lambda) that will be called when the grid is being built. The delegate will receive an object from the dataSource as input, and it must return a string representing the ID of the object as output. This is half of what is used to tie parent/child rows together.
- parentIdSelector – This is the other half. This delegate (or lambda) must return the parent ID of the instance that is passed to it.
- attributes – This is a simple key/value pair of attributes to assign to the <table> element of grid.
- sections – You can use this to override how the grid is rendered. For more information, go here.
That’s sounds pretty complicated, but it really isn’t. Here’s how you could use it (I have omitted the markup code for clarity):
It may look a little intimidating, but it’s actually quite simple. An IEnumerable containing Widgets is passed in via the ViewData.Model property. Next, you can see the lambda expression that creates columns (one bound to the widget name, one bound to the description, and a text box that is also bound to the description), followed by two lambdas that deal with IDs.
Ok, so I’ve shown you how to define the extension method, and I’ve shown you how to call the method, now I need to show you how to implement the GridTreeView class. Let’s dive into the code:
That’s quite a bit of code, but most of it is straight forward. There are static properties and fields that you can change based on where the jQuery plug-in is installed. The constructor doesn’t do much other than grab references to the parameters so that they can be used later. The neat stuff starts in the overridden methods from Grid.
So, that’s basically it. If there is sufficient interest, I’ll wrap everything up in a standalone library (with source code) that can be reused. If you want it, leave me a note in the comments.