私はMVCSiteMapProviderに飛び込んでそれをいじっているだけなので、この質問は、私が望むものを達成できないというよりも、設計に関するものです。MvcSiteMapProvider3.3.4を使用する単純なMVC4Webアプリケーションをセットアップしました。
私がそれで達成したいのは、2レベルのサイトナビゲーションを持つことです。1つは水平方向に表示される最上位レベル用で、もう1つは垂直方向に表示されるその下のレベル用です。サブメニューには、現在選択されているノードの下に階層的にあるノードのみを表示する必要があります。さらに、両方のレベルでアクティブノードを強調表示したいので、実際に選択されているノードと、それがサブノードである場合は、親ノードも強調表示します。
私は実際に設定して、結果が希望どおりになるようにすることができましたが、コードでの表示はあまり好きではないので、ここで質問するのは、これがこれを行うための合法的な方法であるか、誰かができるかどうかです。私が現在欠けているベストプラクティスについて教えてください。
これを実現するために私が直面するハードルは次のとおりです。
1)1つのサイトマップファイルのみを使用し、MvcSiteMap.Menu関数のさまざまな呼び出しでさまざまなレベルを表示したい(上記のように、レベル1は水平ファイル、レベル2は垂直ファイル、レベル0はサイトマップのルートノード[見たくない])
2)2番目の問題は、ホームコントローラーのインデックスアクションをルートノードとしてだけでなく、ルートノードのサブノードとしても使用できることです。これは、他のホームコントローラーのアクションを配置するための追加レベルの階層が必要だからです。確かに、これは後で適切なブレッドクラムを表示するためにいくつかの追加の構成を必要とします。これにより、選択された場合に「ホーム」ノードを強調表示することも困難になることが判明したためです。
これを念頭に置いて、次のサイトマップを設定しました。
(web.configセクション)
<siteMap defaultProvider="MvcSiteMapProvider" enabled="true">
<providers>
<clear />
<add name="MvcSiteMapProvider" type="MvcSiteMapProvider.DefaultSiteMapProvider, MvcSiteMapProvider" siteMapFile="~/Mvc.Sitemap" securityTrimmingEnabled="true" cacheDuration="5" enableLocalization="true" scanAssembliesForSiteMapNodes="true" includeAssembliesForScan="" excludeAssembliesForScan="" attributesToIgnore="visibility" nodeKeyGenerator="MvcSiteMapProvider.DefaultNodeKeyGenerator, MvcSiteMapProvider" controllerTypeResolver="MvcSiteMapProvider.DefaultControllerTypeResolver, MvcSiteMapProvider" actionMethodParameterResolver="MvcSiteMapProvider.DefaultActionMethodParameterResolver, MvcSiteMapProvider" aclModule="MvcSiteMapProvider.DefaultAclModule, MvcSiteMapProvider" siteMapNodeUrlResolver="MvcSiteMapProvider.DefaultSiteMapNodeUrlResolver, MvcSiteMapProvider" siteMapNodeVisibilityProvider="MvcSiteMapProvider.FilteredSiteMapNodeVisibilityProvider, MvcSiteMapProvider" siteMapProviderEventHandler="MvcSiteMapProvider.DefaultSiteMapProviderEventHandler, MvcSiteMapProvider" />
</providers>
</siteMap>
(Mvc.Sitemap)
<?xml version="1.0" encoding="utf-8" ?>
<mvcSiteMap xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://mvcsitemap.codeplex.com/schemas/MvcSiteMap-File-3.0"
xsi:schemaLocation="http://mvcsitemap.codeplex.com/schemas/MvcSiteMap-File-3.0 MvcSiteMapSchema.xsd"
enableLocalization="true">
<mvcSiteMapNode title="Home" controller="Home" action="Index">
<mvcSiteMapNode title="Home" controller="Home" action="Index" visibility="!SiteMapPathHelper,*">
<mvcSiteMapNode title="HomeSub" controller="Home" action="Sub">
</mvcSiteMapNode>
</mvcSiteMapNode>
<mvcSiteMapNode title="Menu1" controller="Menu1" action="Index">
<mvcSiteMapNode title="Menu1Sub" controller="Menu1" action="Sub">
</mvcSiteMapNode>
</mvcSiteMapNode>
<mvcSiteMapNode title="Menu2" controller="Menu2" action="Index">
<mvcSiteMapNode title="Menu2Sub" controller="Menu2" action="Sub">
</mvcSiteMapNode>
</mvcSiteMapNode>
</mvcSiteMapNode>
</mvcSiteMap>
(Views \ Shared \ DisplayTemplates \ MenuHelperModel.cshtml)
@model MvcSiteMapProvider.Web.Html.Models.MenuHelperModel
@using System.Web.Mvc.Html
@using MvcSiteMapProvider.Web.Html.Models
<ul id="menu">
@{
string firstUrl = null;
}
@foreach (var node in Model.Nodes) {
string classes = node.IsCurrentNode | node.IsInCurrentPath | ( ((MvcSiteMapProvider.MvcSiteMapNode)SiteMap.CurrentNode).Action == node.Action && ((MvcSiteMapProvider.MvcSiteMapNode)SiteMap.CurrentNode).Controller == node.Controller )
? "current" : "";
if (firstUrl == null)
{
firstUrl = node.Url;
}
else if (node.Url.Contains(firstUrl))
{
classes += " child";
}
<li class="@classes">@Html.DisplayFor(m => node)
@if (node.Children.Any()) {
@Html.DisplayFor(m => node.Children)
}
</li>
}
</ul>
これでメインサイトメニューをレンダリングします
@Html.MvcSiteMap("MvcSiteMapProvider").Menu(0, true, false, 1)
私はこれを「ルートノードからその下のレベルまでメニューを取得します。ルートノードをその子と同じレベルに配置しますが、ルートノードは表示しません」のように読みます。startNodeInChildLevelをfalseに設定し、showStartingNodeをfalseのままにすると、同じ結果が返されると予想されるため、この呼び出しは取得されませんが、そうではありませんか?理解しやすいように、これをどのように書くことができますか?
そして、このような私のサブメニュー
@Html.MvcSiteMap("MvcSiteMapProvider").Menu(2, 1, true)
正直なところ、私もこの呼び出しを本当に理解していません。MvcSiteMap.Menuのさまざまなオーバーロードを試しているときに偶然見つけたのですが、必要なことを正確に実行しているようです(表示されているノードを選択した親の下のノードのみに減らします)。ノード)。誰かがこれについてそれが正確に何をしているのかを明らかにしましたか?
ブレッドクラムが追加されます
@Html.MvcSiteMap("MvcSiteMapProvider").SiteMapPath()
これは私にとってはうまくいくようですが、なぜ私はこれを投稿することさえわざわざするのですか?
MvcSiteMap.Menuの呼び出しは、これを最初に(または最初の12回:-))読んだ人には確かに混乱しているように見えます。
この現在のソリューションについて私が気に入らない2番目のことは、Home-ControllerのIndex-Action-Nodeの可視性設定です。「HomeSub」リンクを選択した場合にホームノードがブレッドクランプに2回表示されないように、そこに配置しました。
3番目のこと:現在のノードが選択されているかどうかを判断するためのより良い方法はありますか(非常に具体的なケースでは、「ホーム」のサブノードでもあるため、「ホーム」が選択されましたか?コントローラーとアクションのチェックをそこに追加しましたIsCurrentNodeはノードが持っているキーを比較しているように見え、残念ながらそれらは異なっているためです。
これは最初は漠然とした質問のように読めますが、ここで議論を始めたくありません。これがこれを行うのに問題のない方法であるかどうか(または、より良い/読みやすい方法であるかどうか)、および誰かがこれらのメニュー呼び出しと、この機能を実現するために私が行った方法で可視性を設定する必要がある理由を説明できます。
これをいじりたい場合は、この「完全な」サンプルプロジェクトをここ(Visual Studio 2012)からダウンロードできます。