#2:アクティブなトップレベルページの表示を差別化する
大抵のサイトでは、サイト内での現在位置を分かりやすく示すために、アクティブなトップレベルページと非アクティブなトップレベルページの表示方法を変えています。とはいえ、「アクティブな」とはどういう意味でしょうか? トップレベルページだけに限らず、アクティブなページは、現在のページと直接的な関係を持っています。例えば、図1の「Home」ページの色は青ではなく白になっています。これは、「Home」ページは「Site Map」ページの親に当たるトップレベルページだからです。「Site Map」ページが他のトップレベルページの下層にある場合は、そのトップレベルページの色が白になり、「Home」ページの色は青になります。
ASP.NET 1.1で親を判別するにはカスタムのアプローチが必要でしたが、ASP.NET 2.0では、SiteMapNode.IsDescendantOf()メソッドを使うことでこの処理を簡単に実現できます。
次のコード例を見てください。
<asp:Repeater ID="rpt" runat="server" DataSourceID="dsBuckets"> <ItemTemplate><%# IsBucketActive((SiteMapNode)Container.DataItem) ? // if the current page belongs to the current bucket "[display active image]" : // else if the current page does not belong // to the current bucket "[display regular image]" %>/ItemTemplate> </asp:Repeater>
RepeaterのItemTemplateが分離コード内でIsBucketActive()メソッドを呼び出し、現在のSiteMapNodeを渡します。IsBucketActive()関数は、CurrentNode.IsDescendentOf(nodeBucket)が真の場合にtrueを返します。
protected bool IsBucketActive(SiteMapNode nodeBucket) { // pages that don't contain an item in Web.sitemap return null if (SiteMap.CurrentNode == null) return false; else return SiteMap.CurrentNode.Equals(nodeBucket) || SiteMap.CurrentNode.IsDescendantOf(nodeBucket); }
IsDescendantOf()関数とSiteMap.CurrentNodeプロパティの組み合わせは強力なツールとなります。既定のXmlSiteMapProviderはすべての情報をメモリに保持するので、パフォーマンスも高速です。次のソリューションでは、Repeaterのネストを必要とする垂直方向のナビゲーションを紹介します。
#3:トップレベルページに従属する第2レベルページ群を表示する
垂直ナビゲーションでは、多くの場合、一番上にトップレベルページ群を表示し、アクティブなトップレベルページの下に第2レベルページ群を表示し、アクティブな第2レベルページの下に第3レベルページ群を表示します(図2を参照)。しかし、たしかRepeaterは階層データを表示できないはずでしたよね? 実は、Repeaterをネストしてデータバインド構文を使用すれば、階層データを表示することができます(詳しくは、「Nested DataGrids Simplify Hierarchical Data Display」を参照してください)。
このソリューションのコードは次のようになります。
<asp:Repeater ID="Buckets" runat="server" DataSourceID="sourceBuckets"> <ItemTemplate> <%# IsBucketActive((SiteMapNode)Container.DataItem) ? String.Format("<a href=\"{0}\"><b>{1}</b></a><br />," ((SiteMapNode)Container.DataItem).Url, ((SiteMapNode)Container.DataItem).Title) : String.Format("<a href=\"{0}\">{1}</a><br />," ((SiteMapNode)Container.DataItem).Url, ((SiteMapNode)Container.DataItem).Title) %> <asp:Repeater ID="Pails" runat="server" DataSource='<%# ((SiteMapNode)Container.DataItem).ChildNodes %>' Visible='<%# IsBucketActive( (SiteMapNode)Container.DataItem) %>'> <ItemTemplate> <%# String.Format(" <a href=\"{0}\">{1} </a><br />," ((SiteMapNode)Container.DataItem).Url, ((SiteMapNode)Container.DataItem).Title) %> </ItemTemplate> </asp:Repeater> </ItemTemplate> </asp:Repeater>
このアプローチでは、ネストの内側のRepeaterが外側のRepeaterの現在のSiteMapNodeを取得し、ChildNodes()関数を介してその子にバインドします。内側のRepeaterのVisibleプロパティとIsBucketActive()関数を組み合わせることで、アクティブなトップレベルページの第2レべルページ群だけを表示することができます。次のソリューションでは、第2レベルページ群を表示するためによく使われているもう1つの方法を紹介します。
ソリューション#4:トップレベルページの下の階層を表示する
先ほどのソリューションでは、トップレベルページのHTMLコードの間に第2レベルページ群を表示する方法を紹介しました。サイトナビゲーションでは、すべてのトップレベルページを描画した後でアクティブなトップレベルページの子ページ群を表示するという処理もよく要求されますが、これには別のアプローチが必要です。その完ぺきな例が図1の第2レベルのナビゲーションです。
このアプローチは単純です。アクティブなトップレベルページの子ページのみを公開する2つ目のSiteMapDataSourceを追加します。
<asp:SiteMapDataSource ID="srcPails" runat="server"
ShowStartingNode="False" StartingNodeOffset="1" />
StartingNodeOffsetを1に設定すると、開始ポイントはトップレベルページから1つ下のレベルに下がるので、現在アクティブなトップレベルページの子ページ群が公開されます。また、StartingNodeOffsetを2に設定すると、アクティブな第2レベルページの下の第3レベルページ群が公開されます。

