Where Was I?

Site navigation becomes much, much easier in ASP.NET 2.0.





Where Was I?

Site navigation becomes much, much easier in ASP.NET 2.0.


By Dave Sussman


Here's the situation: In a vain attempt to get cheap flights to exotic locations I'm setting up a holiday company, allowing flights, car hire, and hotel reservations to be booked online. I want a simple menu structure and an easy-to-use menu. I can easily pick one of the numerous menu controls, but being the fickle person I am, it's likely I'll change the site design every few months. Today I want a tree-view type of menu, but tomorrow ... who knows? I might go for one of those cool horizontal menus. But I have two problems: How to store the menu structure and how to switch between menu styles without rewriting that structure.


With ASP.NET 1.x, I can't solve these problems without doing a considerable amount of work (did I also mention I'm lazy?). I can easily store my site structure, but I might want to move to a completely database driven site. I don't want to have to write reams of code just to display the menu. In short, I want an easy solution to my navigational woes.


ASP.NET 2.0 solves these problems, not by doing away with the need for third-party menu controls or by defining a fixed storage system for the menu organization, but by providing an infrastructure within which page - and control - developers can work. This infrastructure is based around Site Maps. As with much of ASP.NET 2.0, Site Maps are based on a configurable set of Providers, which make the data available to ASP.NET pages and controls. In the technical preview, the only Site Map Provider, which provides a simple hierarchical list of nodes, is for XML files. For example, the Site Map for my travel company could be:





                   url="flights.aspx?to=USA" />


                   url="flights.aspx?to=world" />




This simply defines a Home page, plus a Flights page with two subitems to narrow down the choice of flights. I'll have more menu items in reality, but this example gives you enough to understand the structure. All that's required to activate this as the Site Map for a site is for it to be placed in a file called app.SiteMap (this will be called web.sitemap by Beta 1) in the application root. (Note that it can be placed in locations other than the application root, though placing it in the app root is probably the most common approach.) However, on its own, this doesn't do anything visible; there's no automatic menu generation. To do that you'll need two things: a way to get the data from the Site Map Provider and a way to display it.


Fetching the data from the Site Map Provider is simple because there's a new server control that does it for you:



The SiteMapDataSource control reads the data from either the default Site Map provider (as shown), or, optionally, from a nondefault provider, and presents it to server controls for display. It's easiest to use it with a TreeView control:



The DataSourceId attribute should be set to the SiteMapDataSource control's ID. This is the new codeless data binding style for ASP.NET 2.0; simply link the data provider and data consumer controls together.


After creating a basic page with just two server controls and a bit of layout, I have a site (see Figure 1).


Figure 1. Here a TreeView control bound to a SiteMapDataSource control shows how the XML Site Map file is displayed in a hierarchical manner. The title attribute of the XML file is bound to the Text property of the tree node and the URL attribute is bound to the NavigateUrl property.


Where Am I?

Simple, isn't it? One XML file and two server controls and you have a workable menu. However, this isn't the end of my problems because I want each page to show where it's located in the menu hierarchy. This might not seem important because you have a tree of all the pages, but it's easy to collapse the tree branches, and then you're unsure of your place in the menu structure. Once again ASP.NET 2.0 comes to the rescue with a server control:



Because the SiteMapPath is integrated with the Site Map infrastructure (the overall infrastructure is referred to as Site Navigation), it automatically shows the navigational path. For example, when I create the Flights page and place a SiteMapPath control on it, my site looks like that shown in Figure 2.


Figure 2. This site has a SiteMapPath control added to the page. All levels in the navigational structure are visible with hyperlinks for levels other than the current.


By default the SiteMapPath control shows the root of the menu structure on the left and the current page (or node) on the right, but this is configurable. In fact, the entire layout is configurable; you can change the font of the nodes, how they're displayed, the separator, and so on. For example, consider this code (note that the font name property will be "font-names" in Beta 1):












  PathSeparator=" -::- " />


Here several attributes are configured. The NodeStyle defines the style for all nodes, unless RootNodeStyle and CurrentNodeStyle override it. In this code the RootNodeStyle and CurrentNodeStyle are defined; therefore, NodeStyle only affects nodes between the root node and the current node. The PathSeparator allows you to specify a string to separate the nodes. The code I've just demonstrated produces the image shown in Figure 3.


Figure 3. Here's the SiteMapPath control with set styles, which changes the look of each node.


If just changing the separator to a string isn't suitable, you can use the PathSeparatorTemplate:






The string used for the separator is ignored and the contents of the template are used instead. The nodes themselves can also be customized in this fashion by using the RootNodeTemplate, NodeTemplate, and CurrentNodeTemplate items. This gives you complete control over how the SiteMapPath control is displayed.


To use the SiteMapPath control, you don't have to use a SiteMapDataSource control, or indeed have any form of navigation. If the page is within the Site Map file that is associated with the default Site Map provider, the SiteMapPath will display correctly. ASP.NET automatically looks up the current page within the Site Map file if required and constructs the appropriate path.



At this point you still haven't written any code - it's all been done declaratively - but there's a time when you might want to. For example, the TreeView control might not be to your liking as a menu. You might want to have a similar indented view but use simple links for navigation, or perhaps you want a horizontal menu when you select a menu item and it shows the subitems. It's likely that there will be controls to do this for you, but there's no reason why you can't write them yourself. In the Alpha product, the Site Map is exposed to the developer through a Page-level property called SiteMap. In Beta 1, the Page-level property disappears; however, you call static properties on the SiteMap class instead. For example, you call SiteMap.CurrentNode.


The SiteMap object has properties such as RootNode. RootNode is an instance of a SiteMapNode; SiteMapNodes have properties such as HasChildNodes and ChildNodes to allow navigation through the Site Map itself. For instance, to build a simple vertical menu using links, you could iterate through the ChildNodes collection recursively, as I've shown in Figure 4.