avigational menus are an obvious requirement for many Web applications, used in nearly every multi-page site, from family sites to multinational e-commerce systems. Until now, developers have relied on third party components or custom code to create and activate browser-based navigational menus; however, maintaining menus manually becomes increasingly difficult as sites grow and change. Even simply adding and deleting menu items or changing fonts and colors can be difficult.
That’s about to change. The upcoming ASP.NET version 2.0 includes a navigational menu capability implemented in an easy-to-use and flexible Menu control. This article covers the basics of using the new Menu control, including how to change its appearance, how to bind it to data, and how to cache menus for increased scalability.
What Does the Menu Control Do?
The Menu control provides features that help you develop both static and dynamic menus. When rendered in the browser, static menus are fully expanded all the time; in other words, the entire structure is visible, and a user can click on any part at any time (see Figure 1). In contrast, dynamic menus display only a portion of the menu initially; other portions (submenus) appear when users hover the mouse pointer over a parent menu item (see Figure 2).
You configure the content of the Menu control in one of three ways: by entering the menu items directly in the control at design time, via code at runtime, or by binding the control to a data source.
You can control the appearance, orientation, and content of the Menu control easily without writing any complex code. In addition to basic visual properties, the control supports ASP.NET control skins and themes. And of course, you have complete programmatic access to the Menu control’s object model so you can create menus and menu items and set properties dynamically. Like other ASP.NET controls (and unlike many third party controls), the new ASP.NET Menu control supports adaptive rendering, meaning it renders its content appropriately for different types of devices and browsers, so you can write and maintain a single version of the control rather than maintaining separate versions for different devices.
Drilling Into the Menu Control
|Figure 3. Parts of a Menu Control: The figure shows the ASP code that defines a menu, with the various parts labeled.|
The Menu control derives from the System.Web.UI.WebControls.HierarchicalDataBoundControl class. This class acts as a logical container for a Menu control. It’s convenient to think of Menu controls as consisting of three parts: control properties, item style properties, and items. Figure 3 shows the ASP code that defines a menu with the three parts labeled.
Looking at Figure 3, the first section helps you define various properties for the menu control. The second section specifies styles to apply to the various menu item types, and the third section defines the menu items themselves. Note the way the code nests submenu items within the root “Home” menu.
Static and dynamic menus have separate but parallel style properties. Table 1 lists several important Menu control style properties and descriptions.
Table 1. Important Menu Control Properties: The menu lists the name and description of several important Menu control style properties and descriptions.
|Menu item style||Description|
|DynamicHoverStyle||This property controls the appearance of a dynamic menu item when the mouse pointer is positioned over it.|
|DynamicMenuItemStyle||This property controls the appearance of menu items within a dynamic menu.|
|DynamicMenuStyle||This property controls the appearance of a dynamic menu.|
|DynamicSelectedStyle||This property controls the appearance of a dynamic menu item when the user selects it from the menu.|
|StaticHoverStyle||This property controls the appearance of a static menu item when the mouse pointer is positioned over it.|
|StaticMenuItemStyle||This property controls the appearance of the menu items in a static menu.|
|StaticMenuStyle||This property controls the appearance of a static menu.|
|StaticSelectedStyle||This property controls the appearance of a static menu item when the user selects it from the menu.|
Take a closer look at the third section in Figure 3?the
A MenuItem has four important properties: Text, Value, NavigateUrl, and ImageUrl. The Menu control displays the Text property value as the visible name for each menu item. You use the Value property used to store any additional data about the menu item, such as data it should pass to the PostBack event associated with the menu item. When clicked, a menu item can navigate to another Web page indicated by the NavigateUrl property. If you don’t set the NavigateUrl property for a menu item, the Menu control simply submits the page to the server for processing when a user clicks that menu item. You’re not limited to text menu items, either; using the ImageUrl property, you can optionally display an image in a menu item rather than a simple text string.
A Static Display Example
You control a Menu’s static display behavior using the StaticDisplayLevels property, which indicates how many levels the control should display all the time, counting from the root of the menu. For example, if you have a Menu with three levels and you set StaticDisplayLevels to 3, the control will display all the levels statically. If you set StaticDisplayLevels to 2 instead, the control expands and displays only the first two levels statically?the third level will appear dynamically.
|Figure 4. Static Menu Display: The figure shows the menu defined in the code from Listing 1.|
|Author’s Note: The minimum value for the StaticDispalyLevels property is 1; the control will throw an exception if you set the StaticDisplayLevels property value to zero or to a negative number. In contrast, setting StaticDisplayLevels to a value greater than the number of levels in the menu has no adverse affect.|
Listing 1 shows an ASP.NET page containing a menu that displays all its levels statically. Note that the code in Listing 1?sets the StaticDisplayLevels property value to 5. Even though the example doesn’t have that many levels, the Menu control doesn’t throw an exception; it simply displays all its levels as static. Figure 4 shows how the menu looks in a browser.
A Dynamic Display Example
|Figure 5. Dynamic Menu Control. The figure shows how the dynamic menu code in Listing 2 looks when rendered in a browser.|
The MaximumDynamicDisplayLevels value plays a key role in displaying menus dynamically. The property specifies how many levels of dynamically-appearing menu nodes the control should display after the initial static display level. For example, if the menu’s StaticDisplayLevels property is 2 and the MaximumDynamicDisplayLevels property is 10, the first two levels would be static while the next ten levels would be dynamic. Listing 2 contains an example.
When you compare the code Listing 2 with that in Listing 1, note that the MaximumDynamicDisplayLevels property is the only addition needed to display the Menu dynamically. Apart from that, Listing 2 adds the StaticSubMenuIndent property to keep the menu indentation consistent. Figure 5 shows how the dynamic version appears in a browser.
Other Interesting Menu Control Features
You’ve seen the basics of creating static and dynamic menus, but to use them efficiently and effectively, you need to explore a couple more properties, see how to populate menus by binding them to data, and see how to cache your menus in Web User Controls.
The code you’ve seen so far displays menu controls vertically; but by changing the Orientation property value to Horizontal, you can display a menu horizontally as shown in Figure 6.
|Figure 6. Horizontal Menu Control: The figure shows how the dynamic menu control example in Listing 2 looks when displayed with the Orientation property set to Horizontal.|
You can change the orientation either at design time or dynamically at run time using the code below.
myMenu.Orientation = Orientation.Horizontal;
The DisappearAfter Property
DisappearAfter is an interesting property that controls the amount of time it takes for the dynamically appearing portion of a menu to disappear after the user’s moves the mouse out of that portion of the menu. The property takes an integer representing the number of milliseconds that the dynamic portion of the control should remain visible after a user moves the cursor out of the dynamic menu area. You can set DisappearAfter dynamically as show below.
myMenu.DisappearAfter = 2000;
Listing 1 and Listing 2 set the DisappearAfter property value to 2000, or two seconds. The default value is 500, or one-half second. If you set the value of DisappearAfter to 0, moving the cursor outside of the Menu control causes it to disappear immediately. Setting the value to -1 essentially causes the pause time to be infinite; the dynamic portion will vanish only when a users clicks somewhere outside of the dynamic portion.
Binding a Menu Control to Data
You can use either of two methods to bind the Menu control to an appropriate data source type. You can bind the Menu control to any data source control, such as a SqlDataSource control, an XmlDataSource control, or a SiteMapDataSource control. To bind to a data source control, set the DataSourceID property of the Menu control to the ID value of the data source control. The Menu control automatically binds to the specified data source control. This is the preferred method to bind to data. However, you can also bind the Menu control to an XmlDocument object or a DataSet containing table relations. To bind to one of these data sources, set the DataSource property of the Menu control to the data source and then call the DataBind method.
Caching a Menu in a Web User Control
While the Menu control works well and is quite flexible, it’s not at all efficient out-of-the-box. If you explore how it works, you’ll find that whenever a client requests a page containing a Menu control, the control converts all the menu item information into meaningful data and sends that to the client for each request?even though the menu may not ever change. For large menus, that processing requires significant server resources for every request. Because most menus remain constant for a Web site, you can avoid the overhead of processing the menu for every request by creating a Web User Control (.ascx) page containing the menu. Doing that lets you cache the .ascx Web User Control file and still use it in your .aspx pages. Caching the page causes ASP.NET to process the menu only the first time it’s requested, or when the cache expires; subsequent requests return the cached content, so your Web application will scale better. Listing 3 shows a Web user control (.ascx) file that caches a Menu control.
The menu defined in Listing 3 is similar to the menu in Listing 2; however note that this version uses places the menu in a Web User Control rather than directly on an .aspx page, and that the page contains an OutPutCache directive for better scalability. This version caches the menu (Duration=”10″) for ten seconds (it will recreate the cached version every ten seconds). If your application needs to change the menu based on user level or some other condition, you can take advantage of the VaryByParam property, which can maintain several versions of a page based on the value of a parameter sent in the request URL?for example, UserLevel=1. The code below shows how to use the Web User Control in Listing 3 (the MenuControl.ascx file) in an .aspx page.
<%@ Page Language="C#" %> <%@ Register TagPrefix="uc1" TagName="MenuControl" Src="MenuControl.ascx" %>