We frequently want to extend the physical hierarchical structure of the website as represented by a SiteMapPath control through a virtual logical structure representing our data. Such hierarchical data could be given by a forum, blog, or a product catalog. To achieve this, we need to handle the SiteMapResolve event of the desired SiteMapProvider. The method that will handle this event needs to return a linked list of SiteMapNode objects that represent our logical hierarchical data and this list needs to be connected to the CurrentNode of the SiteMapProvider used for the SiteMapPath control. The example below shows key steps of how it can be done.
First we create a class containing the event handler method and methods to conveniently add and remove the new delegate.
public static void AddResolveEventHandler(SiteMapProvider p)
{
p.SiteMapResolve +=
new SiteMapResolveEventHandler(ForumSiteMapResolve);
}
public static void RemoveResolveEventHandler(SiteMapProvider p)
{
p.SiteMapResolve -=
new SiteMapResolveEventHandler(ForumSiteMapResolve);
}
protected static SiteMapNode ForumSiteMapResolve(Object sender, SiteMapResolveEventArgs e)
{
...
...
}
In the ForumSiteMapResolve method, first we obtain the SiteMapProvider from the SiteMapResolveEventArgs. After we construct the linked list of SiteMapNode's, we will connect this list to the CurrentNode of this SiteMapProvider. If we want to, we can use a custom SiteMapProvider to provide default values for the new SiteMapNode's. This is what we see do in the code segment below.
SiteMapProvider p = e.Provider;
SiteMapNode rootNode = null;
SiteMapNode groupNode = null;
SiteMapNode forumNode = null;
SiteMapNode threadNode = null;
SiteMapProvider pcustom = SiteMap.Providers["CustomSiteMapProvider"];
if (pcustom != null && pcustom.RootNode != null)
{
rootNode = pcustom.RootNode;
if (rootNode.ChildNodes.Count > 0)
{
groupNode = rootNode.ChildNodes[0];
if (groupNode.ChildNodes.Count > 0)
{
forumNode = groupNode.ChildNodes[0];
if (forumNode.ChildNodes.Count > 0)
{
threadNode = forumNode.ChildNodes[0];
}
}
}
}
Next we construct the linked list of the SiteMapNode's. We create a new SiteMapNode for each hierarchical level of our data and populate its Url and Title properties. In the code below, the "returnNode" variable keeps the reference to the head node of the list to be returned by the event handler. The "curentNode" variable keeps the reference to the growing tail of the list. The list is connected through the ParentNode property of the SiteMapNode objects.
SiteMapNode returnNode = null;
SiteMapNode currentNode = null;
if (State.Instance.ThreadID != null)
{
SiteMapNode newNode = null;
if (threadNode != null)
newNode = threadNode.Clone(false);
else
newNode = new SiteMapNode(p, State.Instance.ThreadID.ToString());
newNode.Url = State.Instance.ThreadViewUrl();
newNode.Title = State.Instance.ThreadName;
if (threadNode == null)
newNode.Description = "Thread";
currentNode = returnNode = newNode;
currentNode.ParentNode = null;
}
if (State.Instance.ForumID != null)
{
SiteMapNode newNode = null;
if (forumNode != null)
newNode = forumNode.Clone(false);
else newNode =
new SiteMapNode(p, State.Instance.ForumID.ToString());
newNode.Url = State.Instance.ForumViewUrl();
newNode.Title = State.Instance.ForumName;
if (forumNode == null)
newNode.Description = "Forum";
if (returnNode == null) currentNode = returnNode = newNode;
else currentNode = currentNode.ParentNode = newNode;
currentNode.ParentNode = null;
}
When the list is complete, we attach the tail to the CurrentNode and return the head from the method.
if (currentNode != null)
currentNode.ParentNode = p.CurrentNode;
return returnNode;
Here is an example showing using the created class to attach and remove the SiteMapResolve event handler to the default static SiteMap.Provider. This is the way it works on this website.
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
SetValues();
if (Config<AppSettings>.Instance.DisplayHostMapPath)
ForumSiteMap.AddResolveEventHandler(SiteMap.Provider);
}
LoadControls();
}
protected void Page_Unload(object sender, EventArgs e)
{
if (!IsPostBack)
{
if (Config<AppSettings>.Instance.DisplayHostMapPath)
ForumSiteMap.RemoveResolveEventHandler(SiteMap.Provider);
}
}
|