When building a left-hand navigation control using a Web.Sitemap file and the default .NET2 sitemap provider, I hit an annoying snag. I wanted my navigation to look like this:
Home
- Welcome
- News
- About
In terms of pages, it would look like this:
Home.aspx
- Welcome.aspx
- News.aspx
- About.aspx
So far so easy. I just wrote a simple routine in the Page.Load of my master page that gets SiteMap.CurrentNode and then iterates back to the root node, rendering the menu as it goes via a repeater:
if(SiteMap.CurrentNode != null)
{
SiteMapNode tempNode = SiteMap.CurrentNode;
if (tempNode == null)
{
return;
}
if(tempNode == SiteMap.RootNode) return;
while(!tempNode.ParentNode.Equals(SiteMap.RootNode))
{
tempNode = tempNode.ParentNode;
}
if(tempNode.ChildNodes.Count != 0)
{
ContextMenuRepeater.DataSource = tempNode.ChildNodes;
ContextMenuRepeater.DataBind();
}
}
The repeater then looks like this:
<li>
<asp:HyperLink runat="server" ID="ContextMenuHyperLink" NavigateUrl='<%# Eval("Url") %>'><%# Eval("Title") %></asp:HyperLink></li>
Well that worked fine, until I came to put some News Articles in. You see, the news articles used a page called NewsArticle.aspx. As that wasn't in the sitemap, my code returned null when it tried to get SiteMap.CurrentNode. Therefore, I couldn't iterate my tree so my menu was appearing blank. As if to make things even trickier, the URL contained a QueryString, e.g. NewsArticle.aspx?article=11.
Thankfully, the Web.Sitemap and provider is kinda clever enough that if I create a node in the Web.Sitemap for NewsArticle.aspx then it's intelligent enough to ignore the QueryString (although note that you CAN include the QueryString in a Web.Sitemap as well, so if for example you were using a CMS whereby every page was on a querystring, it could cater for it, e.g. cms/default.aspx?pageid=1234).
So I put an entry in the Web.Sitemap and hey presto, I got my menu back. Only problem was, I was also getting an ugly 'News Article' item appearing in my navigation. I only wanted to go down to the 'News' level and whilst it might be fine for a breadcrumb trail, my navigation was messed up. I tried putting my own attributes on (e.g. 'visible') and whilst the XML didn't complain, the Sitemap provider didn't know what I was on about. I knew that I could start overwriting methods and events to sort it, or even write my own provider, but I wanted a quick and easy solution because all I was doing was writing a prototype.
Quick and dirty solution then. I was writing out the Url and Title values from the Web.Sitemap into my navigation and wasn't using Description for any reason. I therefore set the Description of the NewsArticle entry to 'DO NOT DISPLAY', and changed my repeater to read like so:
>
<li <%#((string)DataBinder.Eval(Container.DataItem, "Description")) == "DO NOT DISPLAY" ? "style=\"display:none\"" : "TRUE"%>>
<asp:HyperLink runat="server" ID="ContextMenuHyperLink" NavigateUrl='<%# Eval("Url") %>'><%# Eval("Title") %></asp:HyperLink></li>
And that worked. It hides the NewsArticle from my menu but because it's only a display thing on the navigation, it still gets picked up as SiteMap.CurrentNode and works correctly. I also use the Title to set the title of the web browser.
Hope this quick and dirty fix can help someone in a pinch. If there's any other easymode solutions out there let me know.