Examining ASP.NET 2.0's Site Navigation - Part 5
By Scott Mitchell
A Multipart Series on ASP.NET 2.0's Site Navigation |
---|
This article is one in a series of articles on ASP.NET 2.0's site navigation functionality.
SiteMap class;
includes a thorough discussion of the SiteMapPath (breadcrumb) control. |
Introduction
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 SiteMap
class.
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
SiteMapNode
class, which has properties like ChildNodes
, ParentNode
, Title
, 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 SiteMapNode
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 SiteMapNode
instances
that makeup the site map. How you accomplish this depends on the site map provider used. If you use the default site map provider
(XmlSiteMapProvider
,
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
various <siteMapNode>
elements like so:
<?xml version="1.0" encoding="utf-8" ?>
|
With the 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 TreeNodeDataBound
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 Node
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
particular 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 imageUrl
custom
value defined. If it does, it sets the TreeView node's ImageUrl
property to ~/Images/value
,
where value is the value of the SiteMapNode
's imageUrl
attribute.
|

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
SiteMapNodeCollection
object,
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:
<asp:Repeater runat="server" ID="siteMapAsBulletedList" DataSourceID="SiteMapDataSource1">
|
Here we've bound the Repeater siteMapAsBulletedList
to the SiteMapDataSource control SiteMapDataSource1
.
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 ShowStartingNode
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 HeaderTemplate
.)
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 DataSource
to the ChildNodes
property of the current node being used, like:
<asp:Repeater runat="server" ID="siteMapAsBulletedList" DataSourceID="SiteMapDataSource1">
|
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 ID
bulletedList
, and
a SiteMapDataSource with ID
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...)
|
Conclusion
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.
Happy Programming!
Attachments
A Multipart Series on ASP.NET 2.0's Site Navigation |
---|
This article is one in a series of articles on ASP.NET 2.0's site navigation functionality.
SiteMap class;
includes a thorough discussion of the SiteMapPath (breadcrumb) control. |