Examining ASP.NET 2.0's Site Navigation - Part 5By Scott Mitchell
The site navigation features in ASP.NET 2.0 make it easy to define a site map and implement common navigation UI elements, such as a breadcrumb, treeview, and menu. Due to its use of the provide model, you can dictate how to serialize the site map. ASP.NET 2.0 ships with a default implementation that serializes site map information to an XML-formatted file (
Web.sitemap, by default), but as we saw in Part 4 this logic can be customized to garner site map information directly from the file system or through a SQL Server database table. Site navigation can even be configured to use security trimming, which will remove those nodes in the site map for which the currently logged on user does not have authorization to view.
The site map provider model and security trimming features are used to customize the set of site map nodes used by the navigation
Web controls, and afford a great deal of customization. However, there are times where we may want to customize the rendered
output of the navigation control based on the site map data. For example, maybe in our Menu control we want to
display an icon next to each menu item depending on some classification defined for the menu item's corresponding site map
node. Alternatively, the markup rendered by ASP.NET's built-in navigation controls may not suit our needs. Rather than
displaying a TreeView or Menu, we may want to show the site navigation information in a bulleted list. Such functionality is
possible by directly working with the
In this article we'll look at how to accomplish a hodgepodge of customizations when rendering the navigation UI controls. Read on to learn more!
(This article does not explore setting up the site map or the basics of the
SiteMap class or the site navigation
system. Refer to the earlier parts of this article series for such information.)
Adding Custom Attributes to the Site Map's Nodes
In earlier installments of this article series we discussed how a website's logical navigational structure is composed as a site map, with the site map being a hierarchical collection of site map nodes. Each site map node is represented in code as an instance of the
SiteMapNodeclass, which has properties like
Url, and others. The following diagram provides a pictoral representation of a site map; each block in the diagram is a node in the site map.
The properties of the
SiteMapNode class indicate the information that can be stored about a node in the site map.
Rather than limit the site map nodes to just the predefined properties in the
SiteMapNode class, Microsoft
added a generic collection to the class. With this generic collection, you can stuff any values into a
instance and associate it with a string key. This generic collection can be accessed using the following syntax:
These custom values can then be programmatically accessed when working with the site map nodes (such as when displaying them in a Menu), and decisions can be made based on these values.
Of course, before we can work with the custom values we must first assign the custom values to the
that makeup the site map. How you accomplish this depends on the site map provider used. If you use the default site map provider
the one that stores the XML site map in an XML-formatted file), the custom values can be added as additional attributes to the
<siteMapNode> elements. For example, imagine that we wanted to include an image in each node in a TreeView
control, with the image for each node defined in the site map. We could add an
imageUrl attribute to the
<siteMapNode> elements like so:
imageUrl properties defined, we now need to customize the navigation UI control used to display this
information to include the image URL. Let's look at an example using the TreeView control (see Betrand
Le Roy's blog entry Site Map Menu with Icons for
an example of this code using the Menu control instead). Start by adding a SiteMapDataSource to the page and then a
TreeView, binding the TreeView to the SiteMapDataSource. Next, create an event handler for the TreeView's
event. This event fires once for each node in the TreeView after the item has been bound to the TreeView node.
This event handler passes in as its second parameter a
TreeNodeEventArgs instance, which has a
property which returns the TreeView node being databound. The TreeView node has a
DataItem property which returns
the object that's been bound to the TreeView. When using the TreeView to show site map data, the
DataItem is the
SiteMapNode instance in the site map that was bound to the particular TreeView node.
The following code checks to make sure that the current
SiteMapNode instance has a
value defined. If it does, it sets the TreeView node's
ImageUrl property to
where value is the value of the
Please forgive my lack of any semblance of artistic skill...
Creating a Custom Navigation User Interface
ASP.NET 2.0 ships with three controls that are commonly used to display information from the site map:
- The SiteMapPath, which displays a "breadcrumb" showing the user their position in the site map hierarchy (This control was discussed in detail in Part 2 of this article series.)
- The TreeView, which displays all of the nodes in the site map in a collapsible treeview
- The Menu, which displays all of the nodes in the site map in a vertically- or horizontally-aligned menu
SiteMapNodeCollectionobject, which contains the hierarchy of nodes. The TreeView and Menu control then programmatically recurse this collection and build up their menu items and tree nodes appropriately.
We can work with the
SiteMapNodeCollection returned by the SiteMapDataSource on our own, either declaratively
or programmatically. Scott Guthrie has an example of doing just this
in his blog entry Data Tutorial #2: Building our
Master Page and Site Navigation Structure. He uses a Repeater to declaratively, using something similar to the following markup:
Here we've bound the Repeater
siteMapAsBulletedList to the SiteMapDataSource control
Keep in mind that the SiteMapDataSource returns a hierarchical
SiteMapNodeCollection object. The Repeater, not being
a hierarchical data Web control, only enumerates the first "level" of site map nodes returns. That is, it doesn't drill
down into each
SiteMapNode's children nodes. In this example the SiteMapDataSource's
is set to False, which causes the
SiteMapNodeCollection to begin with the second "level" (Books, DVDs, Electroincs,
and Computers). That means for each
SiteMapNode in this second level, the
ItemTemplate will be
instantiated. (The root site map node (Home) is displayed with a bit of markup in the
With the above declarative markup, the following output will be rendered:
This is great for displaying the root site map node and the first level, but what if we want to show additional levels? We
can just add another Repeater in the first Repeater's
ItemTemplate, setting that second Repeater's
ChildNodes property of the current node being used, like:
For C#, the
DataSource property would be set like
DataSource='<%# ((SiteMapNode) Container.DataItem).ChildNodes
The appearance of the bulleted list could be enhanced with a bit of CSS. See Scott Guthrie's blog entry for an example of a much more attractive rendering of the bulleted list example from above.
The declarative approach is limited to only showing as many site map levels as there are embedded Repeaters. That is, if the
Romance node had additional sub-nodes, the above declarative markup wouldn't include them. In order to see them using declarative
markup we'd need to add a third Repeater to the second Repeater's
ItemTemplate. However, that would not display
any site nodes that happened to be four levels deep....
To display an arbitrary depth of nodes in a bulleted list we'll need to programmatically invoke the SiteMapDataSource and
recursively iterate through the
SiteMapNodeCollection object returned. The following code (in VB only, sorry!)
shows how to accomplish this. On the page there's a Label Web control with
a SiteMapDataSource with
siteMapData and its
ShowStartingNode property set to False.
(This code, as well as the earlier examples, are all avaiable for download at the end of this article...)
In this article we saw how to further customize the site navigation system in ASP.NET. The nodes that comprise the site map can have an arbitrary number of custom values associated with them, which can then be examined when working with the site map data. A common example of this is using this custom information to make formatting or appearance-related decisions when rendering a TreeView or Menu. We also saw how to create our own navigation UI elements for greater control over the rendered markup. In this article we saw how to have the site map rendered as a nested, bulleted list, both using declarative and programmatic techniques.