Creating Multi-Level Navigational Menu with the ASP.NET Repeater Control and CSS Styles

Syam Pinnaka here, I am a Senior Developer on the Information Security Tools team focused mainly on building identity management software using Microsoft Forefront Identity Manager (more info about FIM can be found here and well be talking about the work we do on FIM in future post) as well as the Security Portal. The Security Portal is an AJAX “Widget” based portal in which we can host a variety of different security applications and will be part of the Connected Information Security Framework or CISF.

During the Security Portal integration and enhancements for the Risk Tracker project, I found a way to create multi level navigational menu with the ASP.NET Repeater control and CSS styles. In this post I take a step by step approach to creating a two level navigational menu with the ASP.NET repeater control and style it using CSS.

For the sake of the post let’s assume that we want to create a navigational menu as shown below.

First Level - Menu item 1

|------- Second Level - Menu item 1

|-------- Second Level - Menu item 2

First Level - Menu item 2

|------- Second Level - Menu item 3

|------- Second Level - Menu item 4

First Level - Menu item 3

First Level - Menu item 4

Step 1: Create a Test ASP.NET Web Application and Menu User Control.

Create a new ASP.NET web application calling it MultiLevelMenuTestApplication. Right click on project file and choose ‘Add new item’. Select ‘Web User Control’ in the Visual studio installed templates and name it ‘Menu.ascx’. Click ‘Add’.

Step 2: Build Menu Items Lists.

Open the Menu.ascx.cs and add the following MenuItem class inside Menu class.

         private class MenuItem
        {
            string _Title;
            string _Desc;
            string _Url;

            public MenuItem()
            {
            }
            public MenuItem(string title, string desc, string Url)
            {
                _Title = title;
                _Desc = desc;
                _Url = Url;
            }

            public string Title
            {
                get
                {
                    return _Title;
                }
                set
                {
                    _Title = value;
                }
            }

            public string Desc
            {
                get
                {
                    return _Desc;
                }
                set
                {
                    _Desc = value;
                }
            }

            public string Url
            {
                get
                {
                    return _Url;
                }
                set
                {
                    _Url = value;
                }
            }

        }

Create four List<MenuItem> instances of just created MenuItem class.

         List<MenuItem> _FirstLevelMenuItems = new List<MenuItem>();
        List<MenuItem> SecondLevelMenuItems = new List<MenuItem>();
        List<MenuItem> _SecondLevelMenuItems1 = new List<MenuItem>();
        List<MenuItem> _SecondLevelMenuItems2 = new List<MenuItem>();

Add menu Items in the Page_Load event of Menu.ascx user control as shown below.

             //Clear previous if any...
            _FirstLevelMenuItems.Clear();
            _SecondLevelMenuItems1.Clear();
            _SecondLevelMenuItems2.Clear(); 

            //Create first level menu items.
            MenuItem mi1 = new MenuItem("First Level -  Menu item 1", "First Level -  Menu item 1", "#Menu1");
            MenuItem mi2 = new MenuItem("First Level -  Menu item 2", "First Level -  Menu item 2", "#Menu2");
            MenuItem mi3 = new MenuItem("First Level -  Menu item 3", "First Level -  Menu item 3", "#Menu3");
            MenuItem mi4 = new MenuItem("First Level -  Menu item 4", "First Level -  Menu item 4", "#Menu4");

            _FirstLevelMenuItems.Add(mi1);
            _FirstLevelMenuItems.Add(mi2);
            _FirstLevelMenuItems.Add(mi3);
            _FirstLevelMenuItems.Add(mi4);

            //Create second level menu items.
            MenuItem submenuitem1 = new MenuItem("Second Level -  Menu item 1", "Second Level -  Menu item 1", "#SubMenu1");
            MenuItem submenuitem2 = new MenuItem("Second Level -  Menu item 2", "Second Level -  Menu item 2", "#SubMenu2");
            MenuItem submenuitem3 = new MenuItem("Second Level -  Menu item 3", "Second Level -  Menu item 3", "#SubMenu3");
            MenuItem submenuitem4 = new MenuItem("Second Level -  Menu item 4", "Second Level -  Menu item 4", "#SubMenu4");

            _SecondLevelMenuItems1.Add(submenuitem1);
            _SecondLevelMenuItems1.Add(submenuitem2);
            _SecondLevelMenuItems2.Add(submenuitem3);
            _SecondLevelMenuItems2.Add(submenuitem4);
Step 3: Place Two Level Repeater Controls in the User Control.

Open the Menu.ascx source and paste the below code.

 <div>
    <asp:Repeater ID="FirstLevelMenuRepeater" runat="server" OnItemDataBound="FirstLevelMenuRepeater_ItemDataBound">
        <HeaderTemplate>
            <div id="navcontainer">
                <ul id="menuroot">
        </HeaderTemplate>
        <ItemTemplate>
            <li>
                <asp:HyperLink ID="FirstLevelMenu" runat="server" NavigateUrl='<%# DataBinder.Eval(Container.DataItem, "Url") %>'
                    Text='<%# DataBinder.Eval(Container.DataItem, "Title") %>' ToolTip='<%# DataBinder.Eval(Container.DataItem, "Desc") %>'>
                </asp:HyperLink>
                <asp:Repeater ID="SecondLevelMenuRepeater" runat="server" >
                    <HeaderTemplate>
                            <ul id="menusecondlevel">
                    </HeaderTemplate>
                    <ItemTemplate>
                        <li>
                            <asp:HyperLink ID="SecondLevelMenu" runat="server" NavigateUrl='<%# DataBinder.Eval(Container.DataItem, "Url") %>'
                                Text='<%# DataBinder.Eval(Container.DataItem, "Title") %>' ToolTip='<%# DataBinder.Eval(Container.DataItem, "Desc") %>'>
                            </asp:HyperLink>
                        </li>
                    </ItemTemplate>
                    <FooterTemplate>
                        </ul></FooterTemplate>
                </asp:Repeater>                
            </li>
        </ItemTemplate>
        <FooterTemplate>
                </ul>
            </div>
        </FooterTemplate>
    </asp:Repeater>
</div>

Notice in the above code that we placed two Repeater controls one inside the other. The first level Repeater control is with id FirstLevelMenuRepeater and the second level Repeater control is with id SecondLevelMenuRepeater. Each Repeater has a Header, Item and Footer template. Header has an ‘ul’ element and item template has corresponding ‘li’ element. Inside each ‘li’, we have ASP.NET hyperlink with its NavigationalUrl, Text, and ToolTip properties data bound to menu items Lists created in step 2.

Also notice that there is FirstLevelMenuRepeater_ItemDataBound event which will be used to find and bind correct second level menu items to second level repeater control as described in step 4.

Step 4: Data Bind the Repeater controls.

Bind FirstLevelMenuRepeater with _FirstLevelMenuItems in the Page_Load event of Menu.ascx user control as shown below.

 FirstLevelMenuRepeater.DataSource = _FirstLevelMenuItems; 
FirstLevelMenuRepeater.DataBind();

Create an event handler for FirstLevelMenuRepeater_ItemDataBound event as shown below.

 protected void FirstLevelMenuRepeater_ItemDataBound(object sender, RepeaterItemEventArgs e) 
{ 
   if (e.Item.DataItem != null) 
   { 
      string Title = DataBinder.Eval(e.Item.DataItem, "Title").ToString().Trim(); 
      SecondLevelMenuItems.Clear(); 
      GetSubMenuItems(Title, SecondLevelMenuItems); 
      Repeater FourthLevelMenuRepeater = (Repeater)e.Item.FindControl("SecondLevelMenuRepeater"); 
      FourthLevelMenuRepeater.DataSource = SecondLevelMenuItems; 
     FourthLevelMenuRepeater.DataBind(); 
    } 
} 

In the above event handler, we are finding the title of first level menu item and using that title to get corrosponding second level menu items. This is accomplished in GetSubMenuItems code as shown below.

         private void GetSubMenuItems(string Title, List<MenuItem> MenuItems)
        {
            if (Title == "First Level -  Menu item 1" )
            {
                MenuItems = _SecondLevelMenuItems1;
            }
            else if (Title == "First Level -  Menu item 2")
            {
                MenuItems = _SecondLevelMenuItems2;
            }
            SecondLevelMenuItems = MenuItems;
        }
Step 5: Add the Menu Control to Default.aspx page.

Add a reference of Menu user control to Default.aspx as shown below.

Add the below immediately after <%@ Page ... %> directive.

 <%@ Register Src="Menu.ascx" TagName="Menu" TagPrefix="ucMenu" %> 

And add the below inside <form > element.

 <ucMenu:Menu ID="Menu1" runat="server"/>

At this point if we run the solution, we will have the menu items displayed as shown below.

clip_image002

Step 6: Style the Menus.

Right click on project and select ‘Add New item’. Select ‘Style Sheet‘ inside Visual studio installed templates, name the style sheet as Menu.css and click ‘Add’.

We used the following to styles Menu.css.

 /* menu item styles */
#navcontainer
{
 border-left: solid 0px Gray;
    border-Top: solid 0px Gray;
 border-bottom: solid 1px Gray;  
    border-right: solid 1px Gray;   
    height: 400px;
  width : 200px; 
 overflow:hidden;
}
#menuroot
{
 vertical-align :middle;
 font-family: Segoe UI, Verdana, Tahoma, Helvetica, Arial, sans-serif;
   font-size: 11pt ;
   list-style-type:circle;
 list-style-position: inside;            
    margin: 0;
  padding: 15px 0 0 5px;
  color : Maroon ;
    line-height: 2em;
   
} 
#menuroot li 
{ 
   padding:3px;
    text-align: left;   
    vertical-align :middle; 
    
} 
#menuroot a
{
  width: 150px;
   line-height: 2em;
   display:block;  
    text-decoration: underline;
 font-weight: bold;  
    line-height: normal;
} 
#menuroot a:link, #menuroot a:visited
{
    color:Black;    
    text-decoration: none;
  font-weight :lighter  ;
 font-size: 10pt ;
   line-height: normal;
} 
#menuroot a:hover
{
    color:Maroon;   
    text-decoration: none;
  font-size: 10pt ;
   line-height: normal;
}


/* right hand menu second level */
#menusecondlevel
{
    vertical-align :middle;
 font-family: Segoe UI, Verdana, Tahoma, Helvetica, Arial, sans-serif;
   list-style-type:square;
 list-style-position: inside;            
    margin: 0;
  padding: 0 0 0 10px;
    line-height: 1.5em;
} 
#menusecondlevel li 
{ 
 padding:1px;
    text-align: left;   
    vertical-align :middle;
} 
#menusecondlevel a
{
    width: 150px;
   display:block;  
    font-weight: normal;  
  font-size: 3pt ;
    text-decoration: none;      
} 
#menusecondlevel a:link, #menusecondlevel a:visited
{
  color:Black;    
} 
#menusecondlevel a:hover
{
 color:Maroon;   
}

Add a reference of menu.css in menu.ascx as shown below.

 <link href="Menu.css" rel="stylesheet" type="text/css" />

Run the solution and you will see a two level menu with the styles applied as displayed below.

clip_image004

Summary:

We used the ASP.NET Repeater control to create a two level menu item menu control. The same concept can be extended to create menu with any number of sub items levels as explained in this blog post. Please contact me if you need a working example of this blog post. Happy coding!