#4: What's Under Your Bucket?
The previous solution showed how to display pails in between the HTML code for buckets. Displaying children of the active bucket after all buckets have been rendered is also a common requirement of site navigation, but requires a different approach. The second-level navigation in
Figure 1 is a perfect example.
The approach is simple. Add a second SiteMapDataSource that exposes only the children of the active bucket:
<asp:SiteMapDataSource ID="srcPails" runat="server"
ShowStartingNode="False" StartingNodeOffset="1" />
By setting
StartingNodeOffset to
1, the example forces the starting point down one level from the bucket level, thus exposing the children of the currently active bucket. Setting the
StartingNodeOffset to
2 works for third-tier pages under the active second-tier page, and so on.
#5: Lost in a Sea of Breadcrumbs
Displaying breadcrumbs in ASP.NET 2.0 is so ridiculously simple with the SiteMapPath control that this solution goes right to a more interesting problemhiding certain breadcrumbs.
Hiding pages from the list of breadcrumbs is very useful in some circumstances, but its implementation is non-trivial. For example, suppose you want a set of pages to
act as if they are children of the home page, yet
look like third-level pages rather than buckets. Your sitemap might look like this:
- Home (root version)
- Home (bucket version)
- Articles
- Solutions
- ...
The "Privacy Policy" page and the "Article #1" page must use different approaches to display their breadcrumbs. For example, Article #1 should display its breadcrumbs as
Home > Articles > Article #1. It uses the root version of Home
and displays its parent bucket. In contrast, the Privacy policy page should display its breadcrumbs as
Home > Privacy Policy. But if it displays the root version of Home AND its bucket it will display home twice. So the problem is how to hide one of those pages from the breadcrumbs display.
You can solve the problem in three steps. First, by using the
SiteMapPath templates in the page:
<asp:SiteMapPath ID="smp" runat="server" PathSeparator="">
<RootNodeTemplate>
<a href="/Default.aspx" >Home</a>
</RootNodeTemplate>
<NodeTemplate>
<%# (IsSiteMapNodeVisible(Container.SiteMapNode) ?
Eval("Url," " // <a href=\"{0}\">") +
Eval("Title," "{0}</a>") :
"") %>
</NodeTemplate>
<CurrentNodeTemplate>
<%# Eval("Title," " // {0}")%>
</CurrentNodeTemplate>
</asp:SiteMapPath>
Second, by adding a
visible="false" siteMapNode attribute to
Web.sitemap as follows:
<siteMapNode url="/" title="Home">
<siteMapNode url="~/Default.aspx" title="Home" visible="false" />
...
And third, by adding an
IsSiteMapNodeVisible() function that uses the
visible property in the code-behind:
protected bool IsSiteMapNodeVisible(SiteMapNode node) {
// pages that don't contain an item in Web.sitemap return null
if (node == null)
return true;
// most pages won't contain the visible attribute
else if (node["visible"] == null)
return true;
else
// return true unless visible is set to "false"
return !node["Visible"].Equals("false");
}
You should note two things about the preceding solution. First,
Web.sitemap uses two different URL names to refer to
Default.aspx. This is important because without it the .NET Framework will return the error:
Multiple nodes with the same URL 'Default.aspx' were found.
XmlSiteMapProvider requires that sitemap nodes have unique URLs.
The .NET Framework requires URL's to be unique because behind the scenes it stores SiteMapNodes in a Dictionary object in memory. You could also get around this requirement by appending parameters to your URLs (e.g.
Default.aspx?1, and
Default.aspx?2).
Second, note that you cannot use
PathSeparator if you ever plan to hide breadcrumbs. If you do set a path separator, either through the
PathSeparator attribute or the
PathSeparatorTemplate properties, the system displays the separator for your non-visible breadcrumbsresulting in double separators.
The solution above approaches the problem by manually writing the "//" path separator in the
NodeTemplate and
CurrentNodeTemplate. You should note that doing this invalidates any
NodeStyle-Font-Bold type attributes, because those will now apply to the separator as well as to the breadcrumb content. Consequently the
NodeTemplate rolls its own formatting.
Even with the added twist of hiding certain breadcrumbs the ASP.NET 2.0 breadcrumb solution is remarkably simple compared to a custom solution. And what's truly impressive is how easy it is to extend the approach using
SiteMapPath templates and custom attributes.