Evjen c14.tex V2 - 01/28/2008 2:39pm Page 697 Chapter 14: Site Navigation Adding Styles to Dynamic Items Adding styles to the dynamic items of t he menu control is just as easy as adding them to static items. The Menu control has a number of different elements for modifying the appearance of dynamic items, including the following: ❑ < DynamicHoverStyle > ❑ < DynamicItemTemplate > ❑ < DynamicMenuItemStyle > ❑ < DynamicMenuStyle > ❑ < DynamicSelectedStyle > These elements change menu items the same way as the static versions of these elements, but they change only the items that dynamically pop-out from the static items. Listing 14-19 shows an example of apply- ing the hover style to dynamic items. Listing 14-19: Adding a hover style to dynamic items in the menu control <asp:Menu ID="Menu1" runat="server" DataSourceID="Sitemapdatasource1"> <StaticHoverStyle BackColor="DarkGray" BorderColor="Black" BorderStyle="Solid" BorderWidth="1"></StaticHoverStyle> <DynamicHoverStyle BackColor="DarkGray" BorderColor="Black" BorderStyle="Solid" BorderWidth="1"></DynamicHoverStyle> </asp:Menu> This code produces the results shown in Figure 14-22. Figure 14-22 697 Evjen c14.tex V2 - 01/28/2008 2:39pm Page 698 Chapter 14: Site Navigation Changing the Layout of the Menu Items By default, the dynamic menu items are displayed from left to right. This means that, as the items in the menu expand, they are continually displayed in a vertical fashion. You can actually control this behavior, but another option is available to you. The other option is to have the first level of menu items appear directly below the first static item (hori- zontally). You change this behavior by using the Orientation attribute of the Menu control, as shown in Listing 14-20. Listing 14-20: Forcing the menu items to use a horizontal orientation <asp:Menu ID="Menu1" runat="server" DataSourceID="SiteMapDataSource1" Orientation="Horizontal"> </asp:Menu> This code produces the results shown in Figure 14-23. Figure 14-23 The Orientation attribute can take a value of Horizontal or Vertical only. The default value is Vertical . Changing the Pop-Out Symbol As the default, an arrow is used as the pop-out symbol for the menu items generated, whether they are static or dynamic. This is shown in Figure 14-24. Figure 14-24 You are not forced to use this arrow symbol; in fact, you can change it to an image with relatively little work. Listing 14-21 shows how to accomplish this task. 698 Evjen c14.tex V2 - 01/28/2008 2:39pm Page 699 Chapter 14: Site Navigation Listing 14-21: Using custom images <asp:Menu ID="Menu1" runat="server" DataSourceID="SiteMapDataSource1" Orientation="Horizontal" DynamicPopOutImageUrl="myArrow.gif" StaticPopOutImageUrl="myArrow.gif"> </asp:Menu> To change the pop-out symbol to an image of your choice, you use the DynamicPopOutImageUrl or Stat- icPopOutImageUrl properties. The String value these attributes take is simply the path of the image you want to use. Depending on the image used, it produces something similar to what you see in Figure 14-25. Figure 14-25 Separating Menu Items with Images Another nice styling option of the Menu control is the capability to add a divider image to the menu items. You use the StaticBottomSeparatorImageUrl , StaticTopSeparatorImageUrl , DynamicBottom- SeparatorImageUrl ,and DynamicTopSeparatorImageUrl properties depending on where you want to place the separator image. For example, if you wanted to place a divider image under only the dynamic menu items, you use the DynamicBottomSeparatorImageUrl property, as shown in Listing 14-22. Listing 14-22: Applying divider images to dynamic items <asp:Menu ID="Menu1" runat="server" DataSourceID="SiteMapDataSource1" DynamicBottomSeparatorImageUrl="myDivider.gif"> </asp:Menu> All the properties of the Menu control that define the image to use for the dividers take a String value that points to the location of the image. The result of Listing 14-22 is shown in Figure 14-26. 699 Evjen c14.tex V2 - 01/28/2008 2:39pm Page 700 Chapter 14: Site Navigation Figure 14-26 Menu Events The Menu control exposes events such as the following: ❑ DataBinding ❑ DataBound ❑ Disposed ❑ Init ❑ Load ❑ MenuItemClick ❑ MenuItemDataBound ❑ PreRender ❑ Unload One nice event to be aware o f is the MenuItemClick event. This event, shown in Listing 14-23, enables you to take some action when the end user clicks one of the available menu items. Listing 14-23: Using the MenuItemClick event VB Protected Sub Menu1_MenuItemClick(ByVal sender As Object, _ ByVal e As System.Web.UI.WebControls.MenuEventArgs) ’ Code for event here End Sub 700 Evjen c14.tex V2 - 01/28/2008 2:39pm Page 701 Chapter 14: Site Navigation C# protected void Menu1_MenuItemClick(object sender, MenuEventArgs e) { // Code for event here } This delegate uses the MenuEventArgs data class and provides you access to the text and value of the item selected from the menu. Binding the Menu Control to an XML File Just as with the TreeView control, it is possible t o bind the Menu control to items that come from other data source controls provided with ASP.NET 3.5. Although most developers are likely to use the Menu control to enable end users to navigate to URL destinations, you can also use the Menu control to enable users to make selections. As an example, take the previous XML file, Hardware.xml , which was used with the TreeView control from Listing 14-8 earlier in the chapter. For this example, the Menu control works with an XmlDataSource control. When the end user makes a selection from the menu, you populate a Listbox on the page with the items selected. The code for this is shown in Listing 14-24. Listing 14-24: Using the Menu control with an XML file VB <%@ Page Language="VB" %> <script runat="server"> Protected Sub Menu1_MenuItemClick(ByVal sender As Object, _ ByVal e As System.Web.UI.WebControls.MenuEventArgs) Listbox1.Items.Add(e.Item.Parent.Value & " : " & e.Item.Value) End Sub </script> <html xmlns="http://www.w3.org/1999/xhtml"> <head runat="server"> <title>Menu Server Control</title> </head> <body> <form id="form1" runat="server"> <asp:Menu ID="Menu1" runat="server" DataSourceID="XmlDataSource1" OnMenuItemClick="Menu1_MenuItemClick"> <DataBindings> <asp:MenuItemBinding DataMember="Item" TextField="Category"></asp:MenuItemBinding> <asp:MenuItemBinding DataMember="Option" TextField="Choice"></asp:MenuItemBinding> </DataBindings> Continued 701 Evjen c14.tex V2 - 01/28/2008 2:39pm Page 702 Chapter 14: Site Navigation </asp:Menu> <p> <asp:ListBox ID="Listbox1" runat="server"> </asp:ListBox></p> <asp:xmldatasource ID="XmlDataSource1" runat="server" datafile="Hardware.xml" /> </form> </body> </html> C# <%@ Page Language="C#" %> <script runat="server"> protected void Menu1_MenuItemClick(object sender, MenuEventArgs e) { Listbox1.Items.Add(e.Item.Parent.Value + " : " + e.Item.Value); } </script> From this example, you can see that instead of using the < asp:TreeNodeBinding > elements, as we did with the TreeView control, the Menu control uses the < asp:MenuItemBinding > elements to make connections to items listed in the XML file, Hardware.xml . In addition, the root element o f the Menu control, the < asp:Menu > element, now includes the OnMenuItemClick attribute, which points to the event delegate Menu1_MenuItemClick . The Menu1_MenuItemClick delegate includes the data class MenuEventArgs , which enables you to get at both the values of the child and parent e lements selected. For this example, both are used and then populated into the Listbox control, as illustrated in Figure 14-27. Figure 14-27 702 Evjen c14.tex V2 - 01/28/2008 2:39pm Page 703 Chapter 14: Site Navigation SiteMap Data Provider A series of data providers in the form of DataSource controls are available in ASP.NET 3.5. One of these D ataSource controls now at your disposal, which you looked at earlier in the chapter, is the SiteMapDataSource control. This DataSource control was developed to work with site maps and the controls that can bind to them. Some controls do not need a SiteMapDataSource control in order to bind to the application’s site map (which is typically stored in the Web.sitemap file). Earlier in the chapter, you saw this in action when using the SiteMapPath control. This control was able to work with the Web.sitemap file directly — without the need for this data provider. Certain navigation controls, however, such as the TreeView control and the DropDownList control, require an intermediary SiteMapDataSource control to retrieve the site navigation information. The SiteMapDataSource control is simple to use as demonstrated throughout this chapter. The SiteMap- DataSource control in its simplest form is illustrated here: < asp:SiteMapDataSource ID="SiteMapDataSource1" runat="server" / > In this form, the SiteMapDataSource control simply grabs the info as a tree hierarchy (as consistently demonstrated so far). Be aware that a number of properties do change how the data is displayed in any control that binds to the data output. ShowStartingNode The ShowStartingNode property determines whether the root node of the .sitemap file is retrieved with the retrieved collection of node objects. This property takes a Boolean value and is set to True by default. If you are working with the Web.sitemap file shown in Listing 14-1, you construct your SiteMapDataSource control as shown in Listing 14-25 to remove the root node from the collection. Listing 14-25: Removing the root node from the retrieved node collection <%@ Page Language="VB" %> <html xmlns="http://www.w3.org/1999/xhtml"> <head runat="server"> <title>Menu Server Control</title> </head> <body> <form id="form1" runat="server"> <asp:SiteMapDataSource ID="SiteMapDataSource1" runat="server" ShowStartingNode="False" /> <asp:Menu ID="Menu1" runat="server" DataSourceID="SiteMapDataSource1"> </asp:Menu> </form> </body> </html> 703 Evjen c14.tex V2 - 01/28/2008 2:39pm Page 704 Chapter 14: Site Navigation This code produces a menu like the one shown in Figure 14-28. Figure 14-28 From this screenshot, you can see that indeed the root node has b een removed, and the menu shown starts by using all the child nodes of the root node. StartFromCurrentNode The StartFromCurrentNode property causes the SiteMapDataProvider to retrieve only a node collection that starts from the current node of the page being viewed. By default, this is set to False , meaning that the SiteMapDataProvider always retrieves all the available nodes (from the root node to the current node). For an example of this, use the .sitemap file from Listing 14-1 and create a page called Markets.aspx . This page in the hierarchy of the node collection is a child node of the Finance node, as well as having two child nodes itself: U.S. Market Report and NYSE. An example of setting the StartFromCurrentNode property to True is shown in Listing 14-26. Listing 14-26: The Markets.aspx page using the StartFromCurrentNode property <%@ Page Language="VB" %> <html xmlns="http://www.w3.org/1999/xhtml"> <head runat="server"> <title>Menu Server Control</title> </head> <body> <form id="form1" runat="server"> <asp:SiteMapDataSource ID="SiteMapDataSource1" runat="server" StartFromCurrentNode="True" /> <asp:Menu ID="Menu1" runat="server" DataSourceID="SiteMapDataSource1"> </asp:Menu> </form> </body> </html> 704 Evjen c14.tex V2 - 01/28/2008 2:39pm Page 705 Chapter 14: Site Navigation This simple property addition produces the result shown in Figure 14-29. Figure 14-29 StartingNodeOffset The StartingNodeOffset property takes an Integer value that determines the starting point of the hierarchy collection. Be default, this property is set to 0 , meaning that the node collection retrieved by the SiteMapDataSource control starts at the root node. Any other value provides the offset from the root node and, in turn, makes this the new starting point. From the e xample provided in Listing 14-1, you know that the collection starts with the Home page found at Default.aspx , a page that you have seen in numerous examples in this chapter. If you set this property’s value to 1 , the starting point of the collection is one space off the default starting point (the Home page starting at Default.aspx ). For example, if the page using the SiteMapDataSource control is the MarketsUS.aspx page, the node collection starts with the Finance page ( Finance.aspx ). Home Offset 0 News Offset 1 U.S. Offset 2 World Offset 2 Technology Offset 2 Sports Offset 2 Finance Offset 1 Quotes Offset 2 Markets Offset 2 U.S. Market Report Offset 3 NYSE Offset 3 Funds Offset 2 Weather Offset 1 From this hierarchy, you can see how much each node is offset from the root node. Therefore, if you set the StartingNodeOffset property to 1 and you are browsing on the U.S. Market Report page, you can see that the node collection starts with the Finance page ( Finance.aspx ) and the other child nodes of the root node (News and Weather) a re not represented in the node collection as the Finance.aspx page is on the direct hierarchical path of the requested page. 705 Evjen c14.tex V2 - 01/28/2008 2:39pm Page 706 Chapter 14: Site Navigation StartingNodeUrl The StartingNodeUrl property enables you to specify the page found in the .sitemap file from which the node collection should start. By default, the value of this property is empty; but when set to something such as Finance.aspx ,, the collection starts with the Finance page as the root node of the node collection. Listing 14-27 shows an example of using the StartingNodeUrl property. Listing 14-27: Using the StartingNodeUrl property <%@ Page Language="VB" %> <html xmlns="http://www.w3.org/1999/xhtml"> <head runat="server"> <title>Menu Server Control</title> </head> <body> <form id="form1" runat="server"> <asp:SiteMapDataSource ID="SiteMapDataSource1" runat="server" StartingNodeUrl="Finance.aspx" /> <asp:Menu ID="Menu1" runat="server" DataSourceID="SiteMapDataSource1"> </asp:Menu> </form> </body> </html> When the StartingNodeUrl property value is encountered, the value is compared against the url attributes in the Web.sitemap file. When a match is found, the matched page is the one used a s the root node in the node collection retrieved by the SiteMapDataSource control. SiteMap API The SiteMap class is an in-memory representation of the site’s navigation structure. This is a great class for programmatically working around the hierarchical structure of your site. The SiteMap class comes with a couple of objects that make working with the navigation structure easy. These objects (or public properties) are described in the following table. Properties Description CurrentNode Retrieves a SiteMapNode object for the current page RootNode Retrieves a SiteMapNode object that starts from the root node and the rest of the site’s navigation structure Provider Retrieves the default SiteMapProvider for the current site map Providers Retrieves a collection of available, named SiteMapProvider objects Listing 14-28 shows an example of working with some SiteMap objects by demonstrating how to use the CurrentNode object from the Markets.aspx page. 706 . DataMember="Item" TextField="Category">< /asp: MenuItemBinding> < ;asp: MenuItemBinding DataMember="Option" TextField="Choice">< /asp: MenuItemBinding> </DataBindings> Continued 701 Evjen. working with the Web.sitemap file shown in Listing 14-1, you construct your SiteMapDataSource control as shown in Listing 14- 25 to remove the root node from the collection. Listing 14- 25: Removing. example, you can see that instead of using the < asp: TreeNodeBinding > elements, as we did with the TreeView control, the Menu control uses the < asp: MenuItemBinding > elements to make connections