Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Horizontal Submenu with Horizontal Menu using CSS Friendly Menu Control Adapter in C#

0.00/5 (No votes)
27 Jun 2016 1  
Rendering horizontal submenu with horizontal submenu by ASP.NET menu control using CSS friendly menu adapter from a scratch in .NET with C#

What Problem Does This Solution Solve?

By the built in ASP.NET 2.0 or 3.5 menu control is rendered as <table> elements that is difficult to manage by CSS and JavaScript. One can render the menu control output as <ul><li></ul> HTML elements instead of tables using CSS Menu Adapter Control that is easier to emit 100% pure CSS based rendering output.

In another words, for any Data list or in our case Menu Control, if you notice the HTML code by viewing the source of your page what ASP.NET runtime engine generates, you may see a Table based layout, which is of course really difficult to design and not considered a good practice in the new web standards. To overcome that issue, CSS Control Adapter is the answer. It will render div and unorderlist (UL) instead of table which can easily be redesigned using CSS. It means you can now have a standardized approach to create web based controls.

By this article, you can develop a horizontal menu with horizontal submenu from scratch using the ASP.NET menu control.

How Does This Help Someone Else?

Using this article, one can integrate CSS Control Adapter with Menu Control. A control adapter can help to produce CSS friendly HTML without sacrificing the power and flexibility of the original Menu control. For example, the root nodes(main menu) of the menu can be laid out vertically or horizontally and child nodes(sub menu) also can be laid out horizontally or vertically.

Background

There are a few articles on the web for rendering menu by CSS friendly menu adapter. Most of them are for vertical menu with vertical submenu or horizontal menu with vertical submenu. My concentration is horizontal menu with horizontal submenu.

Rendered Menu

Main menu.

HorizontalSubmenu/MainMenu1.png

Screen-shot for hovering on brown colored tab.

HorizontalSubmenu/SubmenuBrown1.png

Screen-shot for hovering on violet colored tab.

HorizontalSubmenu/SubmenuViolet1.png

What is Going On Inside the Code Snippets?

My source code contained the solution summary as shown below:

HorizontalSubmenu/SolutionSummary1.png

How Does the Code Actually Work?

The CSS Friendly Control Adapter overrides the default HTML generated by the ASP.NET Web controls to provide a more standards-based approach to presentation via CSS.
Control Adapters are classes (in our case MenuAdapter class ) that derive via the System.Web.UI.Adapters.ControlAdapter base class, and which implement rendering methods that allow a control adapter to completely customize how the markup of an individual control is rendered.

You can use these control adapter classes as-is to get pure CSS friendly output (no need to change the code), or you can tweak them if you want to customize the rendering output however you want.

ControlAdapters are then registered with ASP.NET by adding a .browser file to the /App_Browsers directory immediately underneath the project's application root. A .browser file includes simple markup like below that allows you to specify which Control Adapter should be used for which control.

<browsers>
  <browser refID="Default">
    <controlAdapters>
      <adapter controlType="System.Web.UI.WebControls.Menu"
               adapterType="CSSFriendly.MenuAdapter" />    
    </controlAdapters>
  </browser>
  <browser id="W3C_Validator" parentID="default">
    <identification>
      <userAgent match="^W3C_Validator" />
    </identification>
    <capabilities>
      <capability name="browser"              value="W3C Validator" />
      <capability name="ecmaScriptVersion"    value="1.2" />
      <capability name="javascript"           value="true" />
      <capability name="supportsCss"          value="true" />
      <capability name="supportsCallback"     value="true" />
      <capability name="tables"               value="true" />
      <capability name="tagWriter"            value="System.Web.UI.HtmlTextWriter" />
      <capability name="w3cdomversion"        value="1.0" />
    </capabilities>    
  </browser>
</browsers>

You can customize different control adapters for different browsers if you want, or just define them for "Default" to apply them by default to all browsers that visit your app.

Once you do that, you are good to go - and can use standard CSS stylesheets to customize all style information.

How To Add Your Menu Item

If you want to add a menu item with some submenu items by adding new node at your site map, you should only set menu style for your new class .AspNet-Menu-4-Left, .AspNet-Menu-4-Center, .AspNet-Menu-4-Right and submenu style for your new class AspNet-SubMenu-3 in MenuStyle.css.

/* AspNet-Menu-1 indicate its for root menu item 1,  
	AspNet-Menu-2 for root menu item 2 and so on */
/*Each root menu item has three parts Left, Center and Right */
.AspNet-Menu-1-Left { background:url(../Images/Menu/blueleft.png) no-repeat; 
	width:15px; float:left; height:31px;}
.AspNet-Menu-1-Center { background:url(../Images/Menu/bluemid.png) repeat-x; 
	width:146px; float:left; height:31px;}
.AspNet-Menu-1-Right { background:url(../Images/Menu/blueright.png) no-repeat; 
	width:15px; float:left; height:31px;}

.AspNet-Menu-2-Left { background:url(../Images/Menu/brownleft.png) no-repeat; 
	width:15px; float:left; height:31px;}
.AspNet-Menu-2-Center { background:url(../Images/Menu/brownmid.png) repeat-x; 
	width:146px; float:left; height:31px;}
.AspNet-Menu-2-Right { background:url(../Images/Menu/brownright.png) no-repeat; 
	width:15px; float:left; height:31px;}

.AspNet-Menu-3-Left { background:url(../Images/Menu/violetleft.png) no-repeat; 
	width:15px; float:left; height:31px;}
.AspNet-Menu-3-Center { background:url(../Images/Menu/violetmid.png) repeat-x; 
	width:146px; float:left; height:31px;}
.AspNet-Menu-3-Right { background:url(../Images/Menu/violetright.png) no-repeat; 
	width:15px; float:left; height:31px;}
/* AspNet-SubMenu-1 indicate its for submenu of 2nd menu ,  
	AspNet-Menu-2 for submenu of 3rd menu 
AspNet-Menu-3 for submenu of 4th menu and so on */
.AspNet-SubMenu-1{ position:absolute;left:0px; background-color :#c5b26f;}
.AspNet-SubMenu-2 { position:absolute; left:0px; background-color:#b188df;}		

Here AspNet-SubMenu-1 indicates it's for submenu of 2nd menu instead of 1st menu because 1st menu has no submenu items here.

Key CSS for Horizontal Submenu

Menu.css contains the following key CSS for horizontal submenu with horizontal menu.

/* -------------------------------------------------------------------------- */
/* When the Menu control's Orientation property is Horizontal the adapter 
/* wraps the menu with DIV */
/* whose class is AspNet-Menu-Horizontal. 
/* This allows us to force the top tier of the menu to layout */
/* horizontally, whereas all subsequent tiers of the menu lay out vertically. */

.AspNet-Menu-Horizontal ul.AspNet-Menu li
{
    float: left;
}

.AspNet-Menu-Horizontal ul.AspNet-Menu li li
{
    float: left;
}

Rendering <ul><li></ul> Elements

At MenuAdapter.cs, BuildItems method is responsible for dynamically rendering <ul><li></ul> elements based menu.

private void BuildItems(MenuItemCollection items, bool isRoot, HtmlTextWriter writer)
        {
            if (items.Count > 0)
            {
                writer.WriteLine();

                writer.WriteBeginTag("ul");
                if (isRoot)
                {
                    writer.WriteAttribute("class", "AspNet-Menu");
                }
                else
                {
                    writer.WriteAttribute("class", "AspNet-SubMenu-"+subMenuNo);
                    subMenuNo++;
                }
                 //subMenuNo=1 means, this is 1st SubMenu, 
                 //2 means this is 2nd Submenu and so on
                writer.Write(HtmlTextWriter.TagRightChar);
                writer.Indent++;
                int rootItemNo = 1;
                foreach (MenuItem item in items)
                {
                    if(items.Contains(firstMenuItem))
                        // rootItemNo=1 means, this is 1st rootItemNo, 
                        // 2 means this is 2nd rootItemNo, etc.
                        BuildItem(item, writer, true, rootItemNo); 
                    else
                        //Here IsRootItem=false so no need rootItemNo 
                        BuildItem(item, writer, false, 0); 
                    rootItemNo++;
                }

                writer.Indent--;
                writer.WriteLine();
                writer.WriteEndTag("ul");
            }
        }  

Enhanced ASP.NET 4.0 Menu Control

ASP.NET 4.0 makes things easier for web developers by providing “RenderingMode” properties. Here we can specify RenderMode of an ASP.NET Menu control which defines what will be the HTML Render Content Type. By default, the mode is “List” which means control will be rendered as ul/li.

See Abhijit Jana's technical Blog CSS Friendly Menu Control in ASP.NET 4.0.

Points of Interest

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here