A Semi-Dynamic Sitemap Solution

I was creating a website which had pages with multiple views. I wanted a fairly simple sitemap solution, without creating any custom sitemap provider, which could show the current view name in the breadcrumb trail like this -

Home » Parent Page » Current Page » Current View 1
Home » Parent Page » Current Page » Current View 2

So here’s what I did to achieve that -

MasterPage.Master:

<%@ Master Language="C#" AutoEventWireup="true" CodeFile="MasterPage.master.cs" Inherits="MasterPage" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title>CMS ::</title>
</head>
<body>
    <form id="form1" runat="server">
        <div>
            <asp:SiteMapPath ID="SiteMapPath1" runat="server" OnPreRender="SiteMapPath1_PreRender" PathSeparator=" :  " RenderCurrentNodeAsLink="True">
            </asp:SiteMapPath>
        </div>
        <div>
            <asp:ContentPlaceHolder ID="ContentPlaceHolder1" runat="server">
            </asp:ContentPlaceHolder>
        </div>
    </form>
</body>
</html>

MasterPage.master.cs:

using System;
using System.Data;
using System.Configuration;
using System.Collections;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
using System.Collections.Generic;

public partial class MasterPage : System.Web.UI.MasterPage
{
    private string _currentViewName = string.Empty;
    public string CurrentViewName
    {
        get { return _currentViewName; }
        set { _currentViewName = value; }
    }
    protected void Page_Load(object sender, EventArgs e)
    {
        SiteMap.SiteMapResolve += new SiteMapResolveEventHandler(SiteMap_SiteMapResolve);
    }
    protected void SiteMapPath1_PreRender(object sender, EventArgs e)
    {
        //If there is a current view name defined then add a child node to the breadcrumb trail.
        if (!string.IsNullOrEmpty(CurrentViewName))
        {
            SiteMapNodeItem sepItem = new SiteMapNodeItem(-1, SiteMapNodeItemType.PathSeparator);
            ITemplate sepTemplate = SiteMapPath1.PathSeparatorTemplate;
            if (sepTemplate == null)
            {
                Literal separator = new Literal();
                separator.Text = SiteMapPath1.PathSeparator;
                sepItem.Controls.Add(separator);
            }
            else
            {
                sepTemplate.InstantiateIn(sepItem);
            }
            sepItem.ApplyStyle(SiteMapPath1.PathSeparatorStyle);

            SiteMapNodeItem viewItem = new SiteMapNodeItem(-1, SiteMapNodeItemType.Current);
            Literal viewName = new Literal();
            viewName.Text = CurrentViewName;
            viewItem.Controls.Add(viewName);
            viewItem.ApplyStyle(SiteMapPath1.CurrentNodeStyle);

            SiteMapPath1.Controls.AddAt(-1, sepItem);
            SiteMapPath1.Controls.AddAt(-1, viewItem);
        }
        else //...if not then don't show the current node as a link.
        {
            SiteMapPath mySMP = (SiteMapPath)sender;
            mySMP.RenderCurrentNodeAsLink = false;
            mySMP.DataBind();
        }
    }
    private SiteMapNode SiteMap_SiteMapResolve(Object sender, SiteMapResolveEventArgs e)
    {
        SiteMapNode currentNode = SiteMap.CurrentNode.Clone(true);         

        //If there is a current view defined then set the URLs in the breadcrumb trail 
        //so that they point to the correct view. For example:
        //Home (Home.aspx) > News (News.aspx?View=0) > Edit (News.aspx?View=1)
        if (!string.IsNullOrEmpty(CurrentViewName))
        {
            string currentRequest = e.Context.Request.UrlReferrer.PathAndQuery;

            if (currentNode != null)
                currentNode.Url = currentRequest;
        }

        return currentNode;
    }
}

Now you are all set. To put this code in action, just declare a curent view name like this in your pages wherever needed:

((MasterPage)this.Master).CurrentViewName = "News Listing";

This solution was inspired by this blog post.

If you have any questions or comments, please post them below. If you liked this post, you can share it with your followers or follow me on Twitter!