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.
Screen-shot for hovering on brown colored tab.
Screen-shot for hovering on violet colored tab.
What is Going On Inside the Code Snippets?
My source code contained the solution summary as shown below:
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-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{ 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.
.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++;
}
writer.Write(HtmlTextWriter.TagRightChar);
writer.Indent++;
int rootItemNo = 1;
foreach (MenuItem item in items)
{
if(items.Contains(firstMenuItem))
BuildItem(item, writer, true, rootItemNo);
else
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