Потратив несколько часов на это, я думаю, что нашел хорошее (достаточно :)) решение.
Файл SiteMap
Обратите внимание, что узлы без URL будут указывать на родителя
<siteMap xmlns="http://schemas.microsoft.com/AspNet/SiteMap-File-1.0">
<siteMapNode>
<siteMapNode title="Home" url="Home">
<siteMapNode title="Home" />
<siteMapNode title="xxx" url="Cycle"/>
<siteMapNode title="yyy" url="Survey" />
<siteMapNode title="zzzteam" url="Team" />
</siteMapNode>
...
Класс утилиты для генерации URL
CurrentContext является статической ссылкой на RequestContext
public static string GetPageUrl(SiteMapNode node) {
RouteValueDictionary values = new RouteValueDictionary(CurrentContext.RouteData.DataTokens);
values["page"] = node.Url.Trim('/');
return CurrentContext.RouteData.Route.GetVirtualPath(CurrentContext, values).VirtualPath;
}
События с привязкой к данным в MasterPage
Навигация - это вкладка Telerik, субнавигатор - это меню ASP.Net
private void navigation_TabDataBound(object sender, Telerik.Web.UI.RadTabStripEventArgs e) {
if (!String.IsNullOrEmpty(e.Tab.NavigateUrl)) {
SiteMapNode node = (SiteMapNode) e.Tab.DataItem;
// Is this tab a parent of the current navigation node? Then select it
if (SiteMap.CurrentNode.IsDescendantOf(node)) e.Tab.Selected = true;
e.Tab.NavigateUrl = XRouteHandler.GetPageUrl(node);
}
}
private void subNavigation_MenuItemDataBound(object sender, MenuEventArgs e) {
SiteMapNode itemNode = (SiteMapNode) e.Item.DataItem;
SiteMapNode currentNode = SiteMap.CurrentNode;
// SiteMapNodes without url will point to the parent node
if (String.IsNullOrEmpty(itemNode.Url)) {
itemNode = itemNode.ParentNode;
e.Item.Selectable = true;
}
// Is this menu item the node itself or one of it's parents? Then select it
if (currentNode == itemNode || currentNode.IsDescendantOf(itemNode))
e.Item.Selected = true;
e.Item.NavigateUrl = XRouteHandler.GetPageUrl(itemNode);
}
}
Реализация XmlSiteMapProvider
На данный момент это решение достаточно хорошее, позже мы рассмотрим его, чтобы его подтекстировать:)
public override SiteMapNode FindSiteMapNode(HttpContext context) {
string pageName = context.Request.Url.Segments.Last().Trim('/');
foreach (SiteMapNode node in SiteMap.RootNode.GetAllNodes())
if (node.Url.EndsWith(pageName, StringComparison.InvariantCultureIgnoreCase)) return node;
return SiteMap.RootNode;
}