Display hierarchical data in ASP.net MVC framework

I am playing around recently with MVC Framework and as a apart of my experiments I wanted to display hierarchial data. I want to share my finding with you, I hope you will find this interesting and if you are interested you can download source here.

Simple unordered list

My final goal is to display a nested unordered list, as shown below each item can have sub item up to nth level. In past you might have created this kind of list using XSLT or ASP.net Repeater Control.

The Model with self referencing hierarchy

I have very simple Tab class which can have a collection of sub-tab. this class can be used to create multiple level of tab hierarchy.

public class  Tab {

public int  ID {  get; set;  }
public string  Name {  get; set;  }

public string  Alias {  get; set;  }

public  List<Tab> Tabs {  get; set;  }

The Controller

I have a single controller called TabController it has Index action, it does two things 1) Gets list of tabs from by calling service and 2) Passes that list to view.

public class  TabController : Controller {

public void  Index() {
"tabs" TabService.GetTabs() ;
RenderView( "Index" ) ;

View extension for partials

If you have worked with ROR and MonoRail then you must be familiar with partials. Partial allows you to extract a common pieace of a template into a separate file and then you can use it form other templates. in my case I have to create partial because I want to use it from another template and recursively from itself. Current implementation of the ViewPage in the MVC Framework does not allow me to call another view. So I will need an extrension method which will allow me to call another view. Credit for view extension code goes to Nikhil Kothari

public static class  ViewExtensions {

public static void  RenderPartial( this  ViewPage page, 
string  viewName,  object  viewData) 
        RenderPartialCore(page.Html.ViewContext, viewName, viewData)

private static void  RenderPartialCore(ViewContext viewContext
string  viewName,  object  viewData) 
        Controller controller 
(Controller)viewContext.Controller ;
IViewFactory viewFactory  controller.ViewFactory ;

IView partialView  viewFactory.CreateView(viewContext, 
null , viewData) ;
partialView.RenderView(viewContext) ;


I have two views in /Views/Tab folder first one is  Index.aspx and second is TabPartial.aspx  

Index view is the main view, it does not have any rendering logic it justs calls partial view and passes data.

< %@  Page Language ="C#"  
="System.Web.Mvc.ViewPage"  % >

< %@  Import Namespace ="System.Collections.Generic"  % >
< %@  Import Namespace ="ExperimentsWithMVC.Models"  % >
< %@  Import Namespace ="System.Web.Mvc"  % >
< asp:Content  ID ="Content2"  
< h2 > Tabs </ h2 >
< %  this.RenderPartial( "TabPartial",
        new Dictionary<string, object
        {{ "tabs", ViewData["tabs"] } }); %>
</ asp:Content >

TabPartial.aspx is the partial view, it is responsible for rendering the unordered list, it will recursively call itself to render the sub-tabs. Remember that we are not using any masterpage for the partial template it is ment to be used only from another view.

< %@  Page Language ="C#"  Inherits ="System.Web.Mvc.ViewPage"  % >
< %@  Import Namespace ="System.Collections.Generic"  % >
< %@  Import Namespace ="ExperimentsWithMVC.Models"  % >
< ul >
< %  foreach (Tab tab in ViewData[ "tabs"]  as List<Tab > ) {%>
< li >
< %=  tab.Name % >
< %  if (tab.Tabs ! =  null && tab.Tabs.Count  >  0) { %>
< %  this.RenderPartial( "TabPartial",  
                   new Dictionary<string, object
                   { { "tabs", tab.Tabs } }); %>
< %}  % >
</ li >
< %  }% >
</ ul >

Parting thoughts

In the current implementation(Techincal Preview) of ASP.NET MVC Framework, ViewPage inherits from System.Web.UI.Page class which make it very expensive for above scenerio because of unncecessary page life cycle events. I am sure that next beta version will have lighter implementation of ViewPage.

Bookmark with:
Technorati   Digg   Delicious   StumbleUpon   Facebook
My name is Jigar Desai I share my ideas on this site and you can contact me by filling contact form.