MVC3 Helper for Tabbed Navigation

Posted: January 19, 2011 in CSHTML, MVC
Tags: ,

FYI – This still works for MVC4.

I am using the Razor view engine for this example; in Visual Studio 2010 with MVC 3 web application template. For more explanation, check out Scott Guthrie‘s blog here or here or one of the other many great posts he has written.

I like to use the SiteMap control for an easy horizontal navigation menu at the top of the content area and styled like a tab interface. Adding a few thin borders and the right background colors can create a great tab effect.

The new Razor view engine makes it very easy to create dynamic templates.

  • Create a SiteMap in the root directory of your web application and add some nodes
  • Create an App_Code folder in your solution if you do not have one already
  • Add a new blank partial view file called Helpers.cshtml in the App_Code folder
  • Enter the following into the file –

@helper SiteMapHelper() {
    <ul class="menu">
        @{
        SiteMapNodeCollection topLevelNodes = SiteMap.RootNode.ChildNodes;
        }
        @foreach (SiteMapNode node in topLevelNodes)
        {
        <li @if (SiteMap.CurrentNode == node)
            {
                <text>class="selectedMenuItem"</text>
            }
            >
        <a href="@node.Url">@node.Title</a>
        </li>
        }
    </ul>
}
 

After you build the solution, you will have access to a strongly typed helper in your CSHTML. In the following code snippet, I am calling the sitemap helper in my layout cshtml – With a little CSS Styling, you can make this navigation menu look like tabs. This is almost too easy now! Not like the ‘good ole days’ 😉

<!DOCTYPE html>
<html>
<head>
    <title>@ViewBag.Title</title>
    <link href="@Url.Content("~/Content/Site.css")" rel="stylesheet" type="text/css" />
    <script src="@Url.Content("~/Scripts/jquery-1.4.4.min.js")" type="text/javascript"></script>
</head>

<body>
    <div>

        <div id="header">
            <div id="logindisplay">
                @Html.Partial("_LogOnPartial")
            </div>
            <div id="title">
                <h1><img src="../../Content/images/BigBarBook_Logo.png" alt="BigBarBook.com" /></h1>
            </div>
        </div>
        <div id="horizontalNavigation">
            @Helpers.SiteMapHelper()
        </div>
        <div id="main">
            @RenderBody()
            <div id="footer">
            </div>
        </div>
    </div>
</body>
</html>

Here is the CSS i use; some of this is generated with a new MVC3 project –


#main
{
padding: 15px;
background-color: #fff;
margin-bottom: 30px;
_height: 1px; /* only IE6 applies CSS properties starting with an underscore */
clear:both;
border-left: 1pt solid #DDDDDD;
border-right: 1pt solid #DDDDDD;
border-bottom: 1pt solid #DDDDDD;
}
#horizontalNavigation
{
clear:both;
}
.menu
{
list-style:none;
padding:0px;
margin:0px;
}
.menu li
{
float:left;
}

.menu a
{
display:block;
color:#333333;
padding:5pt 7pt 5pt 7pt;
text-decoration:none;
border-left: 1pt solid #DDDDDD;
border-right: 1pt solid #DDDDDD;
border-top: 1pt solid #DDDDDD;
border-bottom: 1pt solid #DDDDDD;
background-color:#F5F5F5;
}

.selectedMenuItem a
{
background-color: White;
border-bottom: 1pt solid #FFFFFF;
}
***UPDATE***

If you want to security trim your menu you can use something like the following...

@helper SiteMapHelper() {
    <ul>
        @{
        SiteMapNodeCollection topLevelNodes = SiteMap.RootNode.ChildNodes;
        }
        @foreach (SiteMapNode node in topLevelNodes)
        {
            if(node.Roles.Count == 0)
            {
                <li @if (SiteMap.CurrentNode == node)
                    {
                        <text>class="selectedMenuItem"</text>
                    }
                    >
                <a href="@node.Url">@node.Title</a>
                </li>
            }
            foreach (string role in node.Roles)
         {
          if(User.IsInRole(role))
                {
                    <li @if (SiteMap.CurrentNode == node)
                        {
                            <text>class="selectedMenuItem"</text>
                        }
                        >
                    <a href="@node.Url">@node.Title</a>
                    </li>
                    continue;
                }
         }
        }
    </ul>
}
Advertisements
Comments
  1. Andrey says:

    Thank you. It works. But, according to your css, you need add class refernce in tag in helper: .

  2. garfbradaz says:

    This is a nice cleam implementation, well done 🙂

  3. Sanket says:

    Thank you. It was very helpful.
    However, it will helpful for readers if you can post your full style sheet (site.css)

  4. Tarun Juneja says:

    woooooooooooooooow!

    thanks for reminding me that though we are in MVC3 but we must not forget many cool asp.net related api is still there.

    my case simple i wrote this

    @if (Roles.IsUserInRole(“Translator”))
    {
    foreach (SiteMapNode node in System.Web.SiteMap.RootNode.ChildNodes)
    {

    @node.Title

    }
    }

  5. wsj1 says:

    How would sub-menu be implemented?

    • If you wanted to add a submenu using the same technique, you could implement something like this psuedo code –
      *Create function to output markup (I used an unordered list) for a node (passed in as a parameter)
      *Call this function for every top-level node
      *In this function, check to see if the current node being processed has any children.
      *If so, call the function again for every child node. Making this a recursive function

      You would need to add the appropriate CSS and javascript to show/hide the sub nodes. There are many examples on the net for creating interactive menus using an unordered list.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s