Saturday, May 23, 2009 11:23 AM Tanzim Saqib

Building a basic Menu control for ASP.NET MVC

There are two different ways to build controls for ASP.NET MVC as of now. The most common way is by HTML Helper extension methods. You will find such methods being used in numerous places inside Views. Such methods can take any complexity of parameters, yet return only standard HTML tags in string format as response. Our Menu control will render a basic structure of CSS Menu, which appearance can be controlled from the site’s CSS file. So no matter which look & feel you would like to see your menu reflects, you do not have to change your Menu control. You will only have to make changes into your CSS.

Menu       Menu1

The following TextBox method renders an input tag with name “username”:

<%= Html.TextBox("username") %>

This sort of extension methods often become handy when you need to render complex or reusable controls in different Views. Today I will talk about a simple Menu control I built which renders UL/LI tags, but can take parameters ranging from string to complex types such as MvcMenuItem. Let us see an example how we would like to see Menu control to be used:

   1:  <%
   2:      var list = new List<MvcMenuItem>();
   3:   
   4:      list.Add(new MvcMenuItem{ Text = "Home", ActionName = "Index" });
   5:      list.Add(new MvcMenuItem("About", "About", "Home"));
   6:      list.Add(new MvcMenuItem("Feedback", "alert('feedback');"));
   7:  %>
   8:   
   9:  <%= Html.Menu()
  10:      .ClientId("menu")
  11:      .AddRange(list)
  12:      .HtmlAttributes(new { style="color: Red" })
  13:      .Render()
  14:  %>


From the snippet you can see, the Menu control is taking a list of MvcMenuItem class which we will create later, is being invoked from Html class and supports method calls in chain which is known as Fluent Interface. Let us take a look at how many different ways we can add menu item to the Menu control:

MvcMenu Add(MvcMenuItem item)
MvcMenu Add(string text, string actionName, string controllerName, string clientCallbackMethod)
MvcMenu Add(string text, string actionName, string controllerName)
MvcMenu Add(string text, string clientCallbackMethod)
MvcMenu Add(string text)
MvcMenu AddRange(List<MvcMenuItem> items)


I am sure you noticed the return type in every method mentioned above. It is because we have to return the current instance of the class from within every method to support Fluent Interface. Let us also take a look at the class properties of MvcMenuItem which has several constructor overloads, helpful when initializing instances. You will notince ClientCallbackMethod property which indicates if this menu item is meant to be calling a client side method. You pass a JavaScript method/code block the menu item will execute it upon user’s click.

public class MvcMenuItem
{
    public string Text { get; set; }
    public string ActionName { get; set; }
    public string ControllerName { get; set; }
    public string ClientCallbackMethod { get; set; }
}


HtmlHelper
resides in a different assembly than we are building MVC control for. So how would we write extension for it? All we have to do is, reference the System.Web.Mvc assembly and we will write the class inside that namespace too:

namespace System.Web.Mvc
{
    public static class MvcMenuExtensions
    {
        public static MvcMenu Menu(this HtmlHelper helper)
        {
            return new MvcMenu(helper);
        }
    }
}


As we are writing extension method, you will notice we followed the convention of putting it in a static class, and the static method named Menu is taking the HtmlHelper which we will pass to the MvcMenu we will be building. Constructor of the MvcMenu class is important. It takes that HtmlHelper and store it to its private variable so that it can be reused later. We need it to be reused later since we are supporting Fluent Interface.

public MvcMenu(HtmlHelper helper)
{
    Helper = helper;
    Items = new List<MvcMenuItem>();
}


As you can understand MvcMenu is the class we are writing responsible for processing menu items, and rendering. Next part is easy and straight forward. We will implement Render method which will write Menu Items for us:

   1:  public MvcMenu HtmlAttributes(object dictionary)
   2:  {
   3:      HtmlProperties = new RouteValueDictionary(dictionary);
   4:      return this;
   5:  }
   6:   
   7:  public string Render()
   8:  {
   9:      var ulTag = new TagBuilder("ul");
  10:      ulTag.MergeAttribute("id", Id ?? string.Empty);
  11:      ulTag.MergeAttributes(HtmlProperties);
  12:   
  13:      foreach (var item in Items)
  14:      {
  15:          var liTag = new TagBuilder("li");
  16:   
  17:          if(!string.IsNullOrEmpty(item.ClientCallbackMethod))
  18:              liTag.InnerHtml = string.Format("<a href=\"javascript:;\" onclick=\"{1}\">{0}</a>", item.Text, item.ClientCallbackMethod);
  19:          else
  20:              liTag.InnerHtml = Html.LinkExtensions.ActionLink(Helper, item.Text, item.ActionName, item.ControllerName ?? string.Empty);
  21:          
  22:          ulTag.InnerHtml += liTag.ToString();
  23:      }
  24:   
  25:      return ulTag.ToString();
  26:  }


We used the ActionLink method which helps us generate valid URL from Action and Controller name. We will reach up to that point only if there is no ClientCallbackMethod is defined. You will also notice the TagBuilder class which is can render a standard HTML tag for you even with specified style. Also do not forget to add the namespace in web.config:

<namespaces>
	<add namespace="TanzimSaqib.Mvc.Menu"/>
	...
</namespaces>


Download the code. Enjoy.

Filed under: , , ,

Comments

# Building a basic Menu control for ASP.NET MVC - Tanzim Saqib on .NET discovery

Pingback from  Building a basic Menu control for ASP.NET MVC - Tanzim Saqib on .NET discovery

# ASP.NET MVC Archived Blog Posts, Page 1

Tuesday, May 26, 2009 12:46 AM by ASP.NET MVC Archived Blog Posts, Page 1

Pingback from  ASP.NET MVC Archived Blog Posts, Page 1

# re: Building a basic Menu control for ASP.NET MVC

Thursday, May 28, 2009 5:33 PM by Gerardo Contijoch

Great code!

I just migrated a site from ASP.NET classic to ASP.MVC which had a menu based on ULs. I replaced the old hard coded menu with a call to your extension and it worked perfectly from start.

Thank you!

# re: Building a basic Menu control for ASP.NET MVC

Monday, July 13, 2009 11:31 PM by Danny

Hi Tanzim,

Your example is working fine.

However , I'd like to add LINQ to SQL model to the existing project.

How do I create a LINQ to SQL model within your code ?

I tried and get a namesapce error.

I'm new to MVC and using SQL Express 2008 with two tables

with identity as primary keys.

Thanks

# re: Building a basic Menu control for ASP.NET MVC

Tuesday, July 14, 2009 8:43 AM by danny

Hi

Great sample

Tried to linq to sql model and got namespace error whe

Adding using statement

How to do with sql server express

Thanks

# re: Building a basic Menu control for ASP.NET MVC

Sunday, December 06, 2009 12:30 PM by Lew

Your download link is broken. Can you provide another link to the source? Thanks!

# re: Building a basic Menu control for ASP.NET MVC

Monday, December 07, 2009 6:56 PM by Lew Hollerbach

Trying again: The downloadlinks is broken. Please provide a functional link for downloading your example. Thanks.

# re: Building a basic Menu control for ASP.NET MVC

Monday, February 01, 2010 5:32 AM by rupesh

Download url not working...pls send link at my mail. rupesh.gcl2@gmail.com

# re: Building a basic Menu control for ASP.NET MVC

Wednesday, February 03, 2010 3:17 PM by kinger

The link is broken.  Has the file been moved?

Thanks.

# re: Building a basic Menu control for ASP.NET MVC

Wednesday, February 03, 2010 11:16 PM by Tanzim Saqib

Updated download link: weblogs.asp.net/.../MvcMenu.zip

Leave a Comment

(required) 
(required) 
(optional)
(required)