Option 1
One way to do this is to set the starting node explicitly. First, give the starting node an explicit key:
<mvcSiteMapNode title="Help" controller="Help" action="Index" key="HelpKey">
<mvcSiteMapNode title="T1" controller="Help" action="T1" />
<mvcSiteMapNode title="T2" controller="Help" action="T2" />
<mvcSiteMapNode title="T3" controller="Help" action="T3" />
<mvcSiteMapNode title="T4" controller="Help" action="T4" />
<mvcSiteMapNode title="T5" controller="Help" action="T5" />
<mvcSiteMapNode title="T6" controller="Help" action="T6" />
</mvcSiteMapNode>
And use the menu overload:
@Html.MvcSiteMap().Menu(Html.MvcSiteMap().SiteMap.FindSiteMapNodeFromKey("HelpKey"), false, false)
But doing it that way doesn't give you much control.
Option 2
You can also use a custom visibility provider. You can pass custom data to the visibility provider using the sourceMetaData dictionary, so you can create a separate "name" for each menu instance:
@Html.MvcSiteMap().Menu(new { name = "MainMenu" })
@Html.MvcSiteMap().Menu(new { name = "HelpMenu" })
Then your custom visibility provider can use the same logic the FilteredSiteMapNodeVisibilityProvider uses for your custom "name" property:
/// <summary>
/// Filtered SiteMapNode Visibility Provider for use with named controls.
///
/// Rules are parsed left-to-right, first match wins. Asterisk can be used to match any control or any control name. Exclamation mark can be used to negate a match.
/// </summary>
public class CustomFilteredSiteMapNodeVisibilityProvider
: SiteMapNodeVisibilityProviderBase
{
#region ISiteMapNodeVisibilityProvider Members
/// <summary>
/// Determines whether the node is visible.
/// </summary>
/// <param name="node">The node.</param>
/// <param name="sourceMetadata">The source metadata.</param>
/// <returns>
/// <c>true</c> if the specified node is visible; otherwise, <c>false</c>.
/// </returns>
public override bool IsVisible(ISiteMapNode node, IDictionary<string, object> sourceMetadata)
{
// Is a visibility attribute specified?
string visibility = string.Empty;
if (node.Attributes.ContainsKey("visibility"))
{
visibility = node.Attributes["visibility"].GetType().Equals(typeof(string)) ? node.Attributes["visibility"].ToString() : string.Empty;
}
if (string.IsNullOrEmpty(visibility))
{
return true;
}
visibility = visibility.Trim();
// Check for the source HtmlHelper
if (sourceMetadata["HtmlHelper"] == null)
{
return true;
}
string htmlHelper = sourceMetadata["HtmlHelper"].ToString();
htmlHelper = htmlHelper.Substring(htmlHelper.LastIndexOf(".") + 1);
string name = sourceMetadata["name"].ToString();
// All set. Now parse the visibility variable.
foreach (string visibilityKeyword in visibility.Split(new[] { ',', ';' }))
{
if (visibilityKeyword == htmlHelper || visibilityKeyword == name || visibilityKeyword == "*")
{
return true;
}
else if (visibilityKeyword == "!" + htmlHelper || visibilityKeyword == "!" + name || visibilityKeyword == "!*")
{
return false;
}
}
// Still nothing? Then it's OK!
return true;
}
#endregion
}
Then update your configuration to use the names instead of the control types.
<mvcSiteMapNode title="Home" controller="Home" action="Index" changeFrequency="Always" >
<mvcSiteMapNode title="Home" controller="Home" action="Index" visibility="MainMenu,!*">
<mvcSiteMapNode title="T1" controller="Home" action="T1" />
<mvcSiteMapNode title="T2" controller="Home" action="T2"/>
</mvcSiteMapNode>
<mvcSiteMapNode title="Help" controller="Help" action="Index" visibility="HelpMenu,!*">
<mvcSiteMapNode title="T1" controller="Help" action="T1" />
<mvcSiteMapNode title="T2" controller="Help" action="T2" />
<mvcSiteMapNode title="T3" controller="Help" action="T3" />
<mvcSiteMapNode title="T4" controller="Help" action="T4" />
<mvcSiteMapNode title="T5" controller="Help" action="T5" />
<mvcSiteMapNode title="T6" controller="Help" action="T6" />
</mvcSiteMapNode>
</mvcSiteMapNode>
And don't forget to set your custom visibility provider as the default in your configuration.
Using internal DI (web.config):
<appSettings>
<add key="MvcSiteMapProvider_DefaultSiteMapNodeVisibiltyProvider" value="MyNamespace.CustomFilteredSiteMapNodeVisibilityProvider, MyAssemblyName"/>
</appSettings>
Using external DI (in DI module - Ninject example shown):
this.Kernel.Bind<ISiteMapNodeVisibilityProviderStrategy>().To<SiteMapNodeVisibilityProviderStrategy>()
.WithConstructorArgument("defaultProviderName", "MyNamespace.CustomFilteredSiteMapNodeVisibilityProvider, MyAssemblyName");
Note: If you need to toggle a parent node's visibility off but leave the child nodes visible, you should use one of the overloads of Menu(), SiteMap(), or SiteMapPath() that allow you to set the visibilityAffectsDescendants parameter to false. It is true by default.