この記事の目的は、ASP.NET対応のWebサイトに滑らかで使いやすいメニューを作成することです。これを達成するために、ASP.NETメニューWebコントロールの標準機能を使用し、カスケードスタイルシート(CSS)を使用して純粋に外観を強化します。
CSSに精通している人のために、この記事のタイトルは確かに鐘を鳴らします。 ASP.NETメニューコントロールのルックアンドフィールを強化するために使用されるCSSは、「CSSのスライドドア」と題されたリストの広く知られている記事では削減されています。
メニューのルックアンドフィールを改善するために使用されるCSSは、リストの記事で徹底的に説明されています。クレジットが期限になるとクレジット。 CSSを提供してくれたダグラスボウマンに感謝します。あなたがそれに慣れていないなら、最初に彼の記事を必ず読んでください。
この記事の焦点は、ASP.NET環境でこのようなメニューをシミュレートする方法にあります。始めましょう...
Visual Studio 2008を起動し、ASP.NET Webアプリケーションプロジェクトテンプレートを使用して新しいプロジェクトを作成しましょう。このテンプレートは、「default.aspx」という名前のデフォルトのWebフォームを自動的に追加します。エディターで開き、[ナビゲーション]タブの下にあるツールボックスからメニューコントロールを追加します。今すぐウェブサイトを実行すると、空白のページを見つめていることになります。メニューが何でも表示するには、最初にいくつかのデータにバインドする必要があります。
メニューコントロールのデータを定義する最も簡単な方法は、訪問者がWebサイトをナビゲートできるようにすることです。サイトマップにバインドすることです。 「web.sitemap」の提案された名前を使用して、新しいサイトマップ項目をプロジェクトに追加します。サイトマップは、サイトのページを階層的に整理するXMLファイルです。追加の利点は、SiteMapDataSourceコントロールによって自動的に参照されることです。
次に、以下のリストに表示されているように、いくつかのページをサイトマップに追加します。
リスト1 -web.sitemap
<? xml version = " 1.0 " encoding = " utf-8 " ?>
< siteMap xmlns = " http://schemas.microsoft.com/AspNet/SiteMap-File-1.0 " >
< siteMapNode url = " " title = " " description = " " >
< siteMapNode url = " Default.aspx " title = " Home " description = " Take me back to the dasboard " />
< siteMapNode url = " Products.aspx " title = " Products " description = " Browse our catalog " />
< siteMapNode url = " Download.aspx " title = " Download " description = " Download neat stuff " />
< siteMapNode url = " Forum.aspx " title = " Forum " description = " Ask questions on our forum " />
< siteMapNode url = " Contact.aspx " title = " Contact " description = " Contact us " />
</ siteMapNode >
</ siteMap >次に、SiteMapDataSourceコントロールをページに追加し、メニューコントロールのDataSourceIdプロパティをデータソースのIDに設定します。また、デフォルトで垂直になるため、メニューコントロールの方向プロパティを水平に設定します。最後になりましたが、sitemapdatasourceのshowstartingnodeプロパティをfalseに設定します。これを行わないと、ルートノードが表示され、このベースノードをメニューに含めたくありません。コードは、リスト2に表示されるコードに似ているはずです。
リスト2 -default.aspx
< asp:Menu
ID =" Menu1 "
runat =" server "
DataSourceID =" SitemapDataSource1 "
Orientation =" Horizontal "
> </ asp:Menu >
< asp:SiteMapDataSource
ID =" SiteMapDataSource1 "
runat =" server "
ShowStartingNode =" False "
/>ブラウザでページを表示すると、機能的で退屈なメニューが表示されます。
図1-プレーンな水平メニュー

メニューにCSSの適用を開始する前に、最初に対処する必要がある別の問題があります。 Default.aspxページを要求するときに生成される結果のHTMLコードを見てみると、メニューコントロールが最も柔軟なHTMLコードを生成しないことに気付くでしょう。デフォルトでは、各メニュー項目をテーブルにラップします。これは、CSSを簡単に適用するためにそれ自体を提供するものではありません。メニューコントロールがすべてのメニュー項目を含むUNORDERERDリストを生成した方が良いでしょう。
幸いなことに、生成されたHTMLは、コントロールアダプターを使用して調整できます。コントロールアダプターを使用すると、希望するHTMLをレンダリングできます。ありがたいことに、このような制御アダプターはCodePlexで簡単に利用できます。 CSSフレンドリーコントロールアダプターキットは、ASP.NETメニューコントロール用のものを含む、事前に構築されたコントロールアダプターを提供します。
CSSフレンドリーコントロールアダプターを使用するには、次の手順に従います。
ソースコードを使用して、CSSFriendly.dllをコンパイルする必要があります。この記事では、アダプターが使用するCSSの一部を調整する必要があるためです。
CSSFriendlyプロジェクトをソリューションに追加すると、Visual Studio Conversion Wizardがポップアップします。コンバージョンを実行するだけで、すべてがスムーズに進む必要があります。コンバージョンが完了したとき、残っているすべてのものは、ASP.NET WebサイトプロジェクトからCSSFriendlyプロジェクトへの参照を追加することです。
Webサイトを実行して、生成されたHTMLコードを今すぐご覧ください。
リスト3 -CSSフレンドリーなHTMLコード
< div class =" AspNet-Menu-Horizontal " id =" Menu1 " >
< ul class =" AspNet-Menu " >
< li class =" AspNet-Menu-Leaf AspNet-Menu-Selected " >
< a
href =" /Default.aspx "
class =" AspNet-Menu-Link AspNet-Menu-Selected "
title =" Take me back to the dasboard "
> Home </ a
>
</ li >
< li class =" AspNet-Menu-Leaf " >
< a
href =" /Products.aspx "
class =" AspNet-Menu-Link "
title =" Browse our catalog "
> Products </ a
>
</ li >
< li class =" AspNet-Menu-Leaf " >
< a
href =" /Download.aspx "
class =" AspNet-Menu-Link "
title =" Download neat stuff "
> Download </ a
>
</ li >
< li class =" AspNet-Menu-Leaf " >
< a
href =" /Forum.aspx "
class =" AspNet-Menu-Link "
title =" Ask questions on our forum "
> Forum </ a
>
</ li >
< li class =" AspNet-Menu-Leaf " >
< a href =" /Contact.aspx " class =" AspNet-Menu-Link " title =" Contact us "
> Contact </ a
>
</ li >
</ ul >
</ div >物事は今見上げています。
注:CSSFriendlyAdapters.Browserファイルを使用すると、どのCSSフレンドリーコントロールアダプターを使用するかを指定できます。私は、私が使用したいものを除くすべてのアダプターにコメントするハバビットを作ります。このようにして、他のコントロールは「適応」されず、デフォルトのHTMLを生成し続けます。
メニューコントロール用のアダプターの上のリストに表示されているコードからわかるように、 <ul> 、 <li> 、 <a>タグに必要なCSSクラスを自動的に挿入します。これにより、これらを定義しなければならないことからトラブルが節約されます。
また、1ページがメニューなどの単一のアダプターコントロールを含むことも非常に一般的です。各コントロールに明確なルックアンドフィールが必要な場合は、適応コントロールのためにCSSSELECTRECTORCLASSを設定します。たとえば、次のようにCSSSELECTORCLASSプロパティの値を設定する場合があります。
リスト4 -CSSSELECTORCLASSプロパティ
< asp:Menu
ID =" Menu1 "
runat =" server "
DataSourceID =" SitemapDataSource1 "
Orientation =" Horizontal "
CssSelectorClass =" PrettyMenu "
> </ asp:Menu >その結果、適応制御によって生成されたHTMLコードは、新しいレイヤー( <div> )内に含まれます。
リスト5-生成されたHTMLコードをラップします
< div class =" PrettyMenu " id =" Menu1 " >
<!-- Other HTML code -->
</ div >このプロパティは、CSSフレンドリーアダプターに固有のものであることに注意してください。これは、このライブラリによってサポートされているコントロールに設定できるカスタム(拡張)属性です。フレンドリーアダプターの仕組みに関する詳細情報が必要です。次のリンクを参照してください。
CSSSELECTORCLASSがメニューの周りに個別のレイヤー( <div> )を生成し、自動化されたCSSクラスを所定の位置に生成すると、最終的にメニューのスタイリングを開始する準備が整いました。
使用されるCSSは、A Apart Artualの記事のそれと同時にあります。前に述べたように、この記事の焦点は、CSSの構造ではなく、きちんとした表現メニューを取得するためにASP.NETメニューコントロールに適用する方法に関するものです。完成した結果を図2に示します。
図2-完成した結果

ダウンロードページに、この記事のソースコードを見つけることができます。スタイルシートと必要な画像が含まれています。次の手順を実行して、完成した結果を再現するだけです。
<Pages>ノードのテーマプロパティをデフォルトに設定します。 (リスト6を参照)リスト6 -web.config抜粋
< system .web>
<!-- ... -->
< pages theme = " Default " >
<!-- ... -->
</ pages >
<!-- ... -->
</ system .web>私のソリューションで使用されているCSSは、リストの記事の記事のCSSと同時にありますが、いくつかの変更があります。主に、変化はCSSに優しいアダプターによって適用されるCSS構造と相関しています。
CSSを適用するには、正しい構造を使用する必要があります。 HTMLがフレンドリーなアダプターによって調整されたコントロールをスタイリングするとき、ホワイトペーパーで言及された図を使用するのが便利です。これらの図は、CSSがどのように構成されているかを明確に示しています。
メニューコントロールの図はこちらで見つけることができます。
多くのフォーラムで頻繁に登場した質問の1つは、ユーザーがトップレベルメニューとは別のタブを選択すると変更される水平サブメニューを実装する方法です。これを作成するには、最初にサイトマップを調整する必要があります。
リスト7は、調整されたサイトマップを示しています。
リスト7 -web.sitemap「サブメニュー項目」と
<? xml version = " 1.0 " encoding = " utf-8 " ?>
< siteMap xmlns = " http://schemas.microsoft.com/AspNet/SiteMap-File-1.0 " >
< siteMapNode url = " " title = " " description = " " >
< siteMapNode url = " Default.aspx " title = " Home " description = " Take me back to the dasboard " >
< siteMapNode url = " About.aspx " title = " About us " description = " " />
< siteMapNode url = " Foo.aspx " title = " Foo " description = " " />
< siteMapNode url = " Bar.aspx " title = " Bar " description = " " />
</ siteMapNode >
<!-- ... -->
</ siteMap >Brevityのために、リスト7には、ホームノードのサブメニュー項目(ノード)のみが表示されます。完全なバージョンのソースコードのWeb.Sitemapをご覧ください。このサイトマップを使用してウェブサイトを閲覧すると、図3に示す効果が表示されます。
図3-サブメニュー項目

この効果を無効にするには、リスト8に示すように、メニューコントロールのMaximumDynamicDisplayLevelsプロパティをゼロに設定します。
リスト8 -MaximumDynamicDisPlayLevelsプロパティ
< asp:Menu
ID =" Menu1 "
runat =" server "
DataSourceID =" SitemapDataSource1 "
Orientation =" Horizontal "
CssSelectorClass =" PrettyMenu "
MaximumDynamicDisplayLevels =" 0 "
> </ asp:Menu >次に、2番目のメニューとSiteMapDataSourceコントロールを追加し、リスト9に示すようにプロパティを設定します。
リスト9-サブメニューコントロール
< asp:Menu
ID =" Menu1 "
runat =" server "
DataSourceID =" SitemapDataSource1 "
Orientation =" Horizontal "
CssSelectorClass =" PrettyMenu "
MaximumDynamicDisplayLevels =" 0 "
>
</ asp:Menu >
< asp:Menu
ID =" Menu2 "
runat =" server "
DataSourceID =" SitemapDataSource2 "
Orientation =" Horizontal "
CssSelectorClass =" PrettySubMenu "
>
</ asp:Menu >
< asp:SiteMapDataSource
ID =" SiteMapDataSource1 "
runat =" server "
ShowStartingNode =" False "
/>
< asp:SiteMapDataSource
ID =" SiteMapDataSource2 "
runat =" server "
StartingNodeOffset =" 1 "
ShowStartingNode =" False "
/>基本的に、2番目のメニューに、サイトマップにある2番目のレベルのノードを表示する必要があり、最初のメニューの選択したタブに対応する開始ノードを表示しないでください。
また、2番目のメニューのCSSSeLectorClassは、PrettySubmenuに設定されています。このメニューのCSSは、最初のメニューに類似しています。チェックアウトしたい場合は、ソースコードをダウンロードしてください。ウェブサイトを実行すると、この辛い結果が得られます。
図4-スタイルのサブメニュー項目

最後の問題を解決する必要があります。この問題を説明するには、プロジェクトを再編成する必要があります。
まず、Site.masterというプロジェクトにマスターページを追加しましょう。コード、メニュー、およびデータソースをデフォルト.aspxページからマスターページに移動し、最初のコンテンツプレイスホルダーの直前に配置します。その後、Default.aspxページを安全に削除できます。
次に、プロジェクトにいくつかのWebコンテンツフォームアイテムを追加しましょう。サイトマップの最初のノードとそのサブノードの項目に対応するWebコンテンツフォームを追加します。
これらのWebコンテンツフォームのそれぞれのマスターページとしてsite.masterを選択してください。 Web.sitemapで言及されている他のページは、純粋に説明的な目的のためにあります。
もう一度サイトを起動し、Fooページに移動します。これにより、問題が明らかになります。
図5-選択の問題

サイトマップの下位レベルにナビゲートしたため、トップレベルのメニューは、選択したメニュー項目をマークするメニュー項目がわかりません。これを解決するには、マスターページのコードでいくつかのコーディングを行う必要があります。
リスト10は、コードの必要な一口を示しています。
リスト10-正しいトップレベルのメニュー項目の選択
namespace MenuWebApplication
{
public partial class Site : System . Web . UI . MasterPage
{
private static string ExtractBaseUrl ( string url )
{
return url . Contains ( "?" ) ? url . Remove ( url . IndexOf ( '?' ) ) : url ;
}
protected void Page_Load ( object sender , EventArgs e )
{
Menu1 . DataBind ( ) ;
// Which node in the site map is currently selected?
SiteMapNode currentNode = SiteMap . CurrentNode ;
if ( currentNode != null )
{
// Obtain the Url of the currently selected node's parent node.
string parentUrl = String . Empty ;
SiteMapNode parentNode = currentNode . ParentNode ;
if ( parentNode != null )
{
parentUrl = ExtractBaseUrl ( parentNode . Url ) ;
}
// Obtain the Url of the currently selected node.
string currentUrl = ExtractBaseUrl ( currentNode . Url ) ;
// Iterate the top level menu tier.
foreach ( MenuItem menuItem in Menu1 . Items )
{
// Compare the menu item's Url against the currently
// selected node's Url or the Url of its parent.
string menuItemUrl = ExtractBaseUrl ( menuItem . NavigateUrl ) ;
if ( ( currentUrl == menuItemUrl ) || ( parentUrl == menuItemUrl ) )
{
// If either matches then mark the top level menu item as selected.
Menu1 . Items [ Menu1 . Items . IndexOf ( menuItem ) ] . Selected = true ;
break ;
}
}
}
}
}
}これで、サブメニュー項目を自由に選択できます。対応するトップレベルのメニュー項目は、訪問者にウェブサイト内の現在の場所に関する視覚的な手がかりを与えるために選択されたままです。
図6-選択の問題が修正されました

コンテキストに敏感な水平サブメニューを備えた派手な表形式メニューを確立するのはかなりの作業ですが、最終的には、滑らかでユーザーフレンドリーなメニューになります。
このようなメニューをユーザーコントロールに実装し、そのユーザーコントロールをWebサイトのマスターページに含めることをお勧めします。ほとんどの場合、そのようなメニューは、ウェブサイト全体で使用されます。