連載:ASP.NET MVC入門【バージョン3対応】

第7回 レイアウト/部分ビューでアプリ共通のデザインを定義

山田 祥寛(http://www.wings.msn.to/
2011/09/22
Page1 Page2 Page3 Page4

■レイアウトに複数のコンテンツ領域を設置する

 レイアウトでは、まずRenderBodyメソッドでメインのコンテンツ領域を表すのが基本だ。個別のビュー・スクリプトで記述された内容は、実行時に「@RenderBody()」と記述された部分に埋め込まれることになる。

 もっとも、より複雑なサイトでは時として、複数のコンテンツ領域を持ちたいということもある。例えば、以下のようなケースである。


図3 複数のコンテンツ領域を必要とするケースのレイアウトも可

 このようなケースに対応するのが、Razorのセクション機能だ。セクションは、レイアウトに埋め込めるサブのコンテンツ領域と考えればよいだろう。

 例えば、以下はデフォルトのレイアウトに対して、ScriptCssセクションを追加した例だ。上の図3における(3)のようなケースを想定している。

<!DOCTYPE html>
<html>
<head>
……中略……
<script src="@Url.Content("~/Scripts/modernizr-1.7.min.js")"
        type="text/javascript"></script>
@RenderSection("ScriptCss", false)
</head>
<!DOCTYPE html>
<html>
<head>
……中略……
<script src="@Url.Content("~/Scripts/modernizr-1.7.min.js")"
        type="text/javascript"></script>
@RenderSection("ScriptCss", False)
</head>
リスト5 JavaScript/スタイルシートを埋め込むべきScriptCssセクションを定義したレイアウト(上:_Layout.cshtml、下:_Layout.vbhtml)

 レイアウトにセクション領域を定義するには、リスト5のようにRenderSectionメソッドを埋め込むだけだ。RenderSectionメソッドの構文は、以下のとおり。

RenderSection(string name [,bool required])
リスト6 RenderSectionメソッドの構文
name:セクション名
required:セクションが必須か(デフォルトはtrue)

 引数requiredがtrueの場合、個別のテンプレートでそのセクションは省略できなくなるので注意してほしい。今回のような例では、引数requiredはfalseとしておくべきだろう(いつもページ固有のJavaScript/スタイルシートが必要であるとは限らないからだ)。本稿ではセクションを1つだけ指定しているが、もちろん、必要に応じて複数のセクションを埋め込んでも構わない。

 このようなセクション付きレイアウトに対してコンテンツを埋め込むには、テンプレート・ファイルで「@sectionブロック」を準備する。例えば以下は、標準で用意されているHome/About.cshtmlもしくはHome/About.vbhtmlに対してScriptCssセクションを追加した例だ。

@{
  ViewBag.Title = "このサイトについて";
}

@section ScriptCss {

  <link href="@Url.Content("~/Content/jquery-ui-1.8.13.custom.css")" rel="stylesheet" type="text/css" />

  <script src="@Url.Content("~/Scripts/jquery-ui-1.8.11.min.js")" type="text/javascript"></script>

  <script src="@Url.Content("~/Scripts/jquery.ui.datepicker-ja.js")" type="text/javascript"></script>
}


<h2>このサイトについて</h2>
<p>
  ここにコンテンツを置いてください。
</p>
@Code
  ViewData("Title") = "このサイトについて"
End Code

@Section ScriptCss

  <link href="@Url.Content("~/Content/jquery-ui-1.8.13.custom.css")" rel="stylesheet" type="text/css" />

  <script src="@Url.Content("~/Scripts/jquery-ui-1.8.11.min.js")" type="text/javascript"></script>

  <script src="@Url.Content("~/Scripts/jquery.ui.datepicker-ja.js")" type="text/javascript"></script>

End Section


<h2>このサイトについて</h2>
<p>
  ここにコンテンツを置いてください。
</p>
リスト7 個別のテンプレートにScriptCssセクションを追加したコード(上:About.cshtml、下:About.vbhtml)

 このように、セクションに埋め込むべきコンテンツを@sectionブロックでくくるわけだ。@section命令の構文は、以下のとおり。

@section name {
  content
}
@Section name
  content
End Section
リスト8 @section命令の構文(上:C#、下:VB)
name:セクション名
content:セクションに埋め込むべきコンテンツ

 ちなみに、セクション領域以外のコンテンツ(=レイアウト上、RenderBodyで定義された領域)は、特別な囲みなどを意識することなく、これまでと同じく記述できる。

 以上を理解できたら、Home/Aboutアクションにアクセスしてみよう。ブラウザの[ソースの表示]から確認すると、確かにScriptCssセクションで定義されたコンテンツが埋め込まれていることが見て取れる。

<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8" />
  <title>このサイトについて</title>
  <link href="/Content/Site.css"
        rel="stylesheet" type="text/css" />

  <script src="/Scripts/jquery-1.5.1.min.js"
          type="text/javascript"></script>

  <script src="/Scripts/modernizr-1.7.min.js"
          type="text/javascript"></script>

  <link href="/Content/jquery-ui-1.8.13.custom.css"
          rel="stylesheet" type="text/css" />

  <script src="/Scripts/jquery-ui-1.8.11.min.js"
          type="text/javascript"></script>

  <script src="/Scripts/jquery.ui.datepicker-ja.js"
          type="text/javascript"></script>

</head>
<body>
リスト9 サンプルの実行結果を[ソースの表示]から確認したコード

■レイアウトを入れ子に配置する

 レイアウトは、入れ子に配置することも可能だ。例えば、以下は個別のテンプレートと、標準で用意されているレイアウト(_Layout.cshtml/_Layout.vbhtml)との間に、子レイアウトである_SubLayout.cshtml/_SubLayout.vbhtmlをかませた例である。

@{
  Layout = "~/Views/Shared/_Layout.cshtml";
}

<img src="http://www.wings.msn.to/image/wings.jpg" />
<hr />
<div>
@RenderBody()
</div>
<hr />
Copyright WINGS Project, 2011
@Code
  Layout = "~/Views/Shared/_Layout.vbhtml"
End Code

<img src="http://www.wings.msn.to/image/wings.jpg" />
<hr />
<div>
@RenderBody()
</div>
<hr />
Copyright WINGS Project, 2011
リスト10 入れ子のレイアウトを定義したコード(上:_SubLayout.cshtml、下:_SubLayout.vbhtml)

 レイアウトを入れ子にするとはいっても、ことさらに特別な構文を要するわけではない。あえていうならば、親レイアウトを呼び出すためにLayoutメソッドを呼び出している点が、子レイアウト固有のルールといえば、ルールだ*3

*3 個別のテンプレートでもLayoutメソッドの指定は必要であったが、これまでは_ViewStart.cshtml/_ViewStart.vbhtmlファイルで共通化していたに過ぎない。

 あとは、個別のテンプレートが子レイアウトを見にいくように、_ViewStart.cshtml/_ViewStart.vbhtmlファイルを以下のように修正すればよい。

@{
  Layout = "~/Views/Shared/_SubLayout.cshtml";
}
@Code
  Layout = "~/Views/Shared/_SubLayout.vbhtml"
End Code
リスト11 子レイアウトを適用するための設定コード(上:_ViewStart.cshtml、下:_ViewStart.vbhtml)

 これで、

個別のテンプレート → 子レイアウト → 親レイアウト

の関連ができたので、さっそく、サンプルを確認してみよう。以下の図のように、確かにレイアウトが入れ子に適用されていることが確認できる。


図4 入れ子にしたレイアウトの適用結果


 INDEX
  ASP.NET MVC入門【バージョン3対応】
  第7回 レイアウト/部分ビューでアプリ共通のデザインを定義
    1.ヘッダ/フッタ/メニューを共通化する − レイアウト
  2.レイアウトに複数のコンテンツ領域を設置/レイアウトを入れ子に配置
    3.部分ビューの基本
    4.アクションを伴う部分ビュー呼び出し/子アクションでフラグメント・キャッシュ
 
インデックス・ページヘ  「ASP.NET MVC入門【バージョン3対応】」


Insider.NET フォーラム 新着記事
  • 第2回 簡潔なコーディングのために (2017/7/26)
     ラムダ式で記述できるメンバの増加、throw式、out変数、タプルなど、C# 7には以前よりもコードを簡潔に記述できるような機能が導入されている
  • 第1回 Visual Studio Codeデバッグの基礎知識 (2017/7/21)
     Node.jsプログラムをデバッグしながら、Visual Studio Codeに統合されているデバッグ機能の基本の「キ」をマスターしよう
  • 第1回 明瞭なコーディングのために (2017/7/19)
     C# 7で追加された新機能の中から、「数値リテラル構文の改善」と「ローカル関数」を紹介する。これらは分かりやすいコードを記述するのに使える
  • Presentation Translator (2017/7/18)
     Presentation TranslatorはPowerPoint用のアドイン。プレゼンテーション時の字幕の付加や、多言語での質疑応答、スライドの翻訳を行える
@ITメールマガジン 新着情報やスタッフのコラムがメールで届きます(無料)

注目のテーマ

Insider.NET 記事ランキング

本日 月間