Directory Freebies VS CheatSheet Forum

RSS

Email

Translate

Home About Archive Privacy Contact Advertise Write for Dev102
Posted by Justin on Apr 14th, 2009 | Filed under ASP.Net, C#, Web Development |

Tab menus are a fairly common thing that I use in a lot of my applications. I like tabs because they help break up large chunks of, usually, related information.

 

At work we use RadControls for Telerik and they have a pretty nice tab menu control that is easy to use and looks good too. The only problem with these controls is that they only work in WebForms like even the default ASP.NET controls. So when I started playing with MVC I quickly realized I would need to spend some time building some of these controls myself.

Based on that realization, the idea for this post was formed and I set to work creating a fair simple control. This control is not meant to be compared with the control from Telerik. Mine is very basic and has very few features.

 

Again, I will be using the default MVC template project as my starting point. I did make a few minor changes to the MasterPage but I will include the finished Visual Studio project with this post so you can take a look for yourself.

The first step is to create the HtmlHelper extension method that will generate our control. This method will do most of the work we need.

   1: public static class MyHtmlHelper
   2: {
   3:     public static string TabbedMenu(this HtmlHelper helper, IEnumerable<MenuTab> tabs)
   4:     {
   5:         var route = helper.ViewContext.RequestContext.RouteData;
   6:         var controller = route.GetRequiredString("controller");
   7:         var action = route.GetRequiredString("action");
   8:         var menu = "\n\n<ul id=\"menu\">";
   9: 
  10:         foreach (var tab in tabs)
  11:         {
  12:             if (controller == tab.Controller && action == tab.Action)
  13:                 menu += "\n\t<li>" + helper.ActionLink(tab.Text, tab.Action,
  14:                 tab.Controller, new { @class = "selected" }) + "</li>";
  15:             else
  16:                 menu += "\n\t<li>" + helper.ActionLink(tab.Text,
  17:                 tab.Action, tab.Controller) + "</li>";
  18:         }
  19:         menu += "\n</ul>\n\n";
  20:         return menu;
  21:     }
  22: }

So what this method does is it accepts an IEnumberable collection of MenuTab. We’ll look at the MenuTab class in just a bit. Next the method gets the names of both the current controller and action. These will be used to determine which tab is currently selected. Then the method uses a foreach to loop through the collection and build out the HTML unordered list. Notice that during the loop we are checking to see if the MenuTab instance’s controller and action match the current controller and action. If they make we apply the selected CSS class to the anchor. Pretty simple stuff.

Note: All this method does is produce the required HTML markup. CSS is used to achieve the tab look.

Now let’s look at the MenuTab class.

   1: public class MenuTab
   2: {
   3:     private MenuTab(string text, string action, string controller)
   4:     {
   5:         Text = text;
   6:         Action = action;
   7:         Controller = controller;
   8:     }
   9: 
  10:     public static MenuTab Create(string text, string action, string controller)
  11:     {
  12:         return new MenuTab(text, action, controller);
  13:     }
  14: 
  15:     public string Text { get; private set; }
  16:     public string Action { get; private set; }
  17:     public string Controller { get; private set; }
  18: }

This class is very simple. It just stores the information we will need to build the links in our menu.

That covers off the extension method and any related code. As you can see I wasn’t kidding when I said it doesn’t have many features. This only meant to should how to get started.

In order to make the menu look like tabs a made a few minor tweaks to the existing Site.css file and added the below class definition to indicate which tab is selected.

   1: ul#menu li a.selected {
   2: background-color: #fff;
   3: color: #000;
   4: }

Now all that is left is to insert our menu into the Site.Master file of our application.

   1: <%= Html.TabbedMenu(new List<MenuTab> {
   2: MenuTab.Create("Home", "Index", "Home"),
   3: MenuTab.Create("About", "About", "Home"),
   4: MenuTab.Create("Services", "Services", "Home"),
   5: MenuTab.Create("Pricing", "Pricing", "Home"),
   6: MenuTab.Create("Contact", "Contact", "Home")
   7: }) %>

I replaced the menu code that was already in the demo with the above code that defines the links in our menu.

So as you can see it was pretty simple to build an extension method to add our own helper method for building a tab like menu. By encapsulating this into a helper method we can now easily reuse it in any application.

You can download a sample project from our Freebies Page

Stay tuned for more great posts from Dev102.com by grabbing the RSS feed. You can also see more posts I have written on my blog or grab my RSS feed.

Tags: , , , , , , , , , ,

13 Responses to “Creating A Tabbed Menu Control For ASP.NET MVC”


  1. Chris Pietschmann Said on Apr 14, 2009 :

    Looks like a good start, but where’s the rest of the code? CSS, JavaScript, etc?

  2. Chris Pietschmann Said on Apr 14, 2009 :

    oh, duh… I just skimmed the article, there’s the CSS. Maybe I should pay attention some times. :)

  3. Jon Said on Apr 22, 2009 :

    Could this work so that instead of a load of MenuTab.Create in the master page it somehow uses data from a database table and does a MenuTab.Create for each item in the database?

    This is a great example that I’ve been looking for, Thanks

  4. Jon Said on Apr 22, 2009 :

    There is a bug in the code, the HTML output is incorrect. This is a working version.

    foreach(var tab in tabs) {
    if(controller == tab.Controller && action == tab.Action)
    menu += “\n\t” + helper.ActionLink(tab.Text, tab.Action,
    tab.Controller, null, new { @class = “selected” }) + “”;
    else
    menu += “\n\t” + helper.ActionLink(tab.Text,
    tab.Action, tab.Controller) + “”;
    }

  5. Neeks Said on Apr 24, 2009 :

    Nice Article to start.

  6. Jon Said on Apr 24, 2009 :

    How would you do it for a nested menu eg/

    Item 1

    SubItem1

    Item 2

    SubItem1

  7. Mike Scott Said on May 21, 2009 :

    Hi Justin

    Nice article. Here are suggestions for improvements:

    1. Use a StringBuilder instead of concatenating strings to create the HTML.
    2. Lose the MenuTab.Create method, it’s redundant. You didn’t previously work with Delphi, did you? ;-)
    3. Add an overload to the MyHtmlHelper that takes a params MenuTab[] parameter so you can lose the new List( {…} ):

  8. Robert Said on Dec 5, 2009 :

    The following code is made available for use with MVC2 “Functional Areas”…
    http://msdn.microsoft.com/en-us/library/ee671793(VS.100).aspx

    download tutorial here…
    http://go.microsoft.com/fwlink/?LinkId=164755

    public class MenuTab
    {
    private MenuTab(string text, string action, string controller, object routevalues)
    {
    Text = text;
    Action = action;
    Controller = controller;
    RouteValues = routevalues;
    }

    public static MenuTab Create(string text, string action, string controller, object routevalues)
    {
    return new MenuTab(text, action, controller, routevalues);
    }

    public string Text { get; private set; }
    public string Action { get; private set; }
    public string Controller { get; private set; }
    public object RouteValues { get; private set; }
    }

    public static class MyHtmlHelper
    {
    public static string TabbedMenu(this HtmlHelper helper, IEnumerable tabs)
    {
    var route = helper.ViewContext.RequestContext.RouteData;
    var action = route.GetRequiredString(”action”);
    var controller = route.GetRequiredString(”controller”);

    var menu = “\n\n”;
    foreach (var tab in tabs)
    {
    if (action == tab.Action && controller == tab.Controller)
    menu += “\n\t” + helper.ActionLink(tab.Text, tab.Action,
    tab.Controller, new { area = tab.RouteValues }, new { @class = “selected” }) + “”;
    else
    menu += “\n\t” + helper.ActionLink(tab.Text, tab.Action,
    tab.Controller, new { area = tab.RouteValues }, null) + “”;
    }
    menu += “\n\n\n”;
    return menu;
    }
    }

    Site.Master page…

    <%= Html.TabbedMenu(new List {
    MenuTab.Create(”Home”, “Index”, “Home”, “”),
    MenuTab.Create(”Blog”, “ShowRecent”, “Blog”, “blog”),
    MenuTab.Create(”Dashboard”, “AddPost”, “Dashboard”, “dashboard”),
    MenuTab.Create(”About”, “About”, “Home”, “”)
    }) %>

  9. Robert Said on Dec 5, 2009 :

    I hope someone might find it useful; I modified the original code by Justin to work with MVC2 Areas.

    Thanks Justin!!

  10. Bart van der Vliet Said on Mar 23, 2010 :

    Thanks for this article, it helped me a lot. For other people who are using this control: Add the namespaces System.Web.Mvc and System.Web.Mvc.Html to access the ActionLink extension method on the HtmlHelper object.

3 Trackback(s)

  1. Apr 14, 2009: DotNetBurner - ASP.net MVC
  2. Apr 15, 2009: 9eFish
  3. Apr 16, 2009: Links 2009-04-16 - Gunnar Peipman's ASP.NET blog

Post a Comment

Write Article for Dev102

Write for Dev102!

We pay for user submitted tutorials and articles that we publish. Anyone can send in a contribution

Learn More