リンクやイメージのURLを指定するときはWebコントロールとチルダ文字(~)を使おう
イメージやリンクをマスターページに追加するとき、<a>
要素や<img>
要素のような定番のHTML要素をどうしても使いたくなるものです。例えば、ホームページへのリンクをマスターページから追加するには、次のようなHTMLを使います。
<a href="Default.aspx">Return To Homepage</a>
このマークアップはマスターページと同じフォルダにあるコンテンツページでは正しく機能しますが、別のフォルダのコンテンツページでは期待どおり機能しません。マスターページがサイトのルートフォルダにあり、そのコンテンツページの1つがFolder1というサブフォルダにあるとき、何が起こるか考えてみましょう。Folder1のコンテンツページでレンダリングされたHTMLは、上に示すマークアップと同じ<a href="Default.aspx">Return To Homepage</a>
になります。従って、このリンクをクリックしたユーザーはFolder1/Default.aspxページに移動し、意図したルートディレクトリのDefault.aspxページには移動しません。この問題を解決するには、HTML要素の<a>
の代わりにHyperLink
コントロールとチルダ文字(~
)を使用して、URLをルートにします。
<asp:HyperLink runat="server" ID="lnkHome" NavigateUrl="~/Default.aspx">Return To Homepage</asp:HyperLink>
NavigateUrl
の値が~/Default.aspxのとき、HyperLink
コントロールはコンテンツページのフォルダを起点とする相対的なURLを生成します。コンテンツページがサイトのルートディレクトリにある場合は<a href="Default.aspx">Return To Homepage</a>
のようなHTMLがレンダリングされ、コンテンツページがサブフォルダ(Folder1など)にある場合は<a href="../Default.aspx">Return To Homepage</a>
のようなHTMLがレンダリングされます。
この問題は<img>
要素にも当てはまります。<img>
に代わって<asp:Image>
Webコントロールを使い、ImageUrl
プロパティでイメージのURLをルートにします。
強い型定義のマスターページ参照を取得するには@MasterTypeディレクティブを使おう
コンテンツページでは常にPage.Master
プロパティで弱い型定義のマスターページ参照が与えられます。マスターページに定義したパブリックなメソッドやプロパティにコンテンツページからアクセスしたければ、強い型定義のマスターページ参照をコンテンツページから取得する必要があります。1つの方法は、弱い型定義の参照を強い型定義の参照へ型変換することです。次の例は、Page.Master
プロパティをマスターページのMasterPageType
型に変換する方法を示しています。
Dim myMasterPage as MasterPageType = CType(Page.Master, MasterPageType)
MasterPageType myMasterPage = Page.Master as MasterPageType;
もっとよいのは、@MasterType
ディレクティブを使うことです。@MasterType
は、コンテンツページの.aspxファイルに追加してマスターページであることを示すディレクティブです。このディレクティブがあると、ASP.NETコンパイラはMaster
という強い型定義のプロパティをページに追加します。次の例はコンテンツページの宣言部から抜粋したもので、@MasterType
ディレクティブが実際にどう使われるかを示しています。
<%@ Page Language="VB" MasterPageFile="~/Site.master" AutoEventWireup="false" CodeFile="..." Inherits="..." %> <%@ MasterType VirtualPath="~/Site.master" %>
このディレクティブを適切に使えば、Page.Master
プロパティが弱い型定義のマスターページ参照を保ちながら、Master
プロパティ(Page.
を省く)が強い型定義の参照を示すようになります(紛らわしいですね)。しかし、このディレクティブとMaster
プロパティを使用すると、Page.Master
プロパティを型変換しなくても、マスターページのパブリックなメソッドやプロパティにアクセスできます。
コンテンツとマスターページの間の相互関係については、チュートリアルの「Interacting with the Master Page from the Content Page」と「Interacting with the Content Page from the Master Page」を参照ください。Scott Allenの記事「Master Pages: Tips, Tricks, and Traps」も参照ください。
マスターページを分けるよりも入れ子にした方がよい
私がこれまで取り組んできたWebサイトの多くは、少しずつ異なるさまざまなセクションを集めたアーチ型のサイトデザインで作られていました。あるEコマースサイトでは、最上部にメニュー、右上隅に利用者とそのカートに関する情報、最下部に法的な決まり文句、左側にセクション別のリンク集...という共通のレイアウトがすべてのページで使われていて、セクションごとのカスタマイズの度合いは小さなものでした。このサイトには、(1)特定の製品に限定されない全般情報ページ、(2)一般商品、(3)商標付き商品、(4)注文調達ページという全部で4つの論理的セクションがありました。ページ最上部の背景イメージはセクションごとに異なり、ページの右上隅のリンク表示領域はページごとに若干の差異が見られました。
これらの差異に対応するために、セクションごとに1つずつ、つまり全部で4つのマスターページをプロジェクト内に設ける方法が検討されました。この方法の問題は、どうしてもマークアップやコードに大量の重複が生じ、サイトデザインやレイアウトマークアップの90%以上がセクション間でまったく同じになることでした。その結果、このアーチ型デザインに何か変更が生じると、4つのマスターページのすべてでマークアップを修正しなければなりませんでした。
もっとよいやり方はマスターページを入れ子にすることです。ASP.NETページにマスターページを割り当てることができるわけだから、当然、マスターページそのものに別のマスターページを割り当ててもかまいません。これを「マスターページを入れ子にする」と言います。このようにマスターページを入れ子にする方法を使えば、すべてのセクションに共通するマークアップやレイアウトを定義したルートマスターページを定義し、その上で4つのセクションごとに入れ子のマスターページを作ることができます。各セクションのコンテンツページでは、それぞれ適切な入れ子のマスターページを使います。この方法のよい点は、アーチ型サイトデザインのマークアップが1つのルートマスターページにまとめられ、入れ子のマスターページにはセクション間で変化する部分だけが定義されることです。これでサイト全体のデザインをずっと簡単に変更でき、しかも変更結果がすべてのセクションにすぐ反映されるようになります。
マスターページを入れ子にする方法の詳細については、Scott Guthrieのブログ記事「Visual Studio 2008 Nested Master Page Support」を参照ください。チュートリアル「Nested Master Pages」も参考になります。
まとめ
マスターページとは、サイト全体のデザインを簡単に定義してコンテンツページに適用する仕組みをASP.NETページ開発者に提供するものです。ASP.NET Webサイトでは常にマスターページを使い、プロジェクトに追加する最初の要素としてまずマスターページを作るようにするとよいでしょう。本稿では、マスターページを使う上でのアドバイスと、ヒントや秘訣を紹介しました。マスターページに関して別のアドバイスやヒントがあれば、どうかご一報ください。皆さんのアイデアを本稿に反映させて他の読者と共有したいと思います。
では、ハッピープログラミング!
参考資料
- 『Master Pages Tutorials』(マスターページに関するトピックを扱ったC#およびVBのチュートリアル10本)
- 『ASP.NET Master Pages』(技術ドキュメント)
- 『ASP.Net 2.0 - Master Pages: Tips, Tricks, and Traps』
- 『Visual Studio 2008 Nested Master Page Support』