#2: Active Buckets: The Plot Thickens
Most sites display active buckets differently from inactive buckets in order to help users identify where they are in the site. But what does active mean? Active pages (the term is not restricted to buckets)contain a direct lineage to the current page. For example, notice that the Home bucket in
Figure 1 is white instead of blue. This is because the Home page is a bucket and the parent of Site Map. If the Site Map page resided within some other bucket, then the Home would be blue, and the other bucket would be white.
Determining ancestry required a custom approach in ASP.NET 1.1. ASP.NET 2.0 simplifies the task with the
SiteMapNode.IsDescendantOf() method.
Consider the following page snippet:
<asp:Repeater ID="rpt" runat="server" DataSourceID="dsBuckets">
<ItemTemplate><%#
IsBucketActive((SiteMapNode)Container.DataItem) ?
// if the current page belongs to the current bucket
"[display active image]" :
// else if the current page does not belong
// to the current bucket
"[display regular image]"
%></ItemTemplate>
</asp:Repeater>
The repeater's
ItemTemplate calls the
IsBucketActive() method in the code-behind and passes in the current SiteMapNode. The
IsBucketActive() function then returns true if
CurrentNode.IsDescendentOf(nodeBucket):
protected bool IsBucketActive(SiteMapNode nodeBucket) {
// pages that don't contain an item in Web.sitemap return null
if (SiteMap.CurrentNode == null)
return false;
else
return SiteMap.CurrentNode.Equals(nodeBucket) ||
SiteMap.CurrentNode.IsDescendantOf(nodeBucket);
}
IsDescendantOf() combined with the
SiteMap.CurrentNode property packs a powerful punch. And since the default XmlSiteMapProvider holds everything in memory, it's fast too. The next solution demonstrates a vertically-oriented navigation, which requires nesting Repeaters.
#3: Putting Pails inside Buckets
Vertical navigations often display buckets (top-level pages), then pails (second-level pages) under the active bucket, and then sometimes tertiary pages under active pails (see
Figure 2). But Repeater's don't display hierarchical data, right? Actually, they can if you nest Repeaters and use the data binding syntax (see my article
Nested DataGrids Simplify Hierarchical Data Display for more details).
 | |
Figure 2: Vertically-oriented Navigation: The navigation bar on the left side of the page in the solution that accompanies this article demonstrates a vertically-oriented navigation. |
The code for this solution might look like:
<asp:Repeater ID="Buckets" runat="server"
DataSourceID="sourceBuckets">
<ItemTemplate>
<%# IsBucketActive((SiteMapNode)Container.DataItem) ?
String.Format("<a href=\"{0}\"><b>{1}</b></a><br />,"
((SiteMapNode)Container.DataItem).Url,
((SiteMapNode)Container.DataItem).Title) :
String.Format("<a href=\"{0}\">{1}</a><br />,"
((SiteMapNode)Container.DataItem).Url,
((SiteMapNode)Container.DataItem).Title)
%>
<asp:Repeater ID="Pails" runat="server" DataSource='<%#
((SiteMapNode)Container.DataItem).ChildNodes %>'
Visible='<%# IsBucketActive(
(SiteMapNode)Container.DataItem)%>'>
<ItemTemplate>
<%# String.Format(" <a href=\"{0}\">{1}
</a><br />,"
((SiteMapNode)Container.DataItem).Url,
((SiteMapNode)Container.DataItem).Title) %>
</ItemTemplate>
</asp:Repeater>
</ItemTemplate>
</asp:Repeater>
With this approach the nested repeater retrieves the current SiteMapNode of the outer repeater and binds to its children via the
ChildNodes() function. The nested repeater's
Visible property combined with the
IsBucketActive() function allows only active buckets to display their pails. The next solution shows another common variation for displaying pails.