しばやん雑記

Azure とメイドさんが大好きなフリーランスのプログラマーのブログ

セクションと子アクションを使って高度なレイアウトを実現する

あまり使ってる人を見ない Razor の新機能であるセクションなんですが、最近の Web サービスのようにサイドバーに情報を表示したりする場合に非常に有用です。

今回はこのブログのサイドバーのようなデザインを ASP.NET MVC 3 で作ってみたいと思います。とりあえず _Layout.cshtml にセクションを表示するためのコードを追加します。

@* SideBar という名前のセクションが定義されている場合は出力 *@
@RenderSection("SideBar", false)

RenderSection メソッドを使うことで指定した名前のセクションを任意の場所に出力できます。2 つ目の引数を true にすると定義されていない場合にエラーを吐きます。

今回は 2 カラムのレイアウトにしたいので、_Layout.cshtml を以下のように修正しました。

<div id="main">
    <div id="body">
        @RenderBody()
    </div>
    <div id="sidebar">
        @RenderSection("SideBar", false)
    </div>
</div>

#body と #sidebar には適当に float を付けてあげてください。とりあえずこの時点で一度実行してみましょう。まだ表示すべきセクションを定義していないので何も表示されていませんが、エラーも表示されていないことが確認できます。

それでは次に表示するセクションを定義しましょう。Home/Index.cshtml に定義を追加します。

@section SideBar
{
    <h3>サイドバー</h3>
}

セクションの定義は @section で行います。中は普通のテキストブロックの扱いになるので、普段通りにタグなどを書くことが出来ます。セクションの定義を追加したので実行してみましょう。

Index.cshtml で定義したセクションが表示されましたね。このようにセクションを使えばメインのコンテンツと別にサイドバーを表示することが出来ました。

しかし、サイドバーに表示する項目が静的なものならば問題ないのですが、普通は動的に内容を出力します。ということは、どこかのアクションでデータを取得する必要があるのですが、表示されているアクションにサイドバー表示用のコードを追加するのは手間ですね。他のページでも表示する場合には、同じコードをアクションに追加する必要があり、メンテナンスにも難ありです。

そこでアクションをインラインで出力することが出来る Html.Action/RenderAction ヘルパーを活用します。別のアクションをインライン表示させることで、親のアクションのコードを変更することなく、さらに別ページでも再利用が可能になります。

それではインラインで表示される専用のアクションを作成します。今回は ModuleController という名前を付けて、News アクションを追加しました。ModuleController のアクションは全て子アクションとして利用するので ChildActionOnly 属性を付けます。

[ChildActionOnly]
public class ModuleController : Controller
{
    public ActionResult News()
    {
        var items = new[]
        {
            "foo",
            "bar",
            "baz"
        };

        return PartialView(items);
    }
}

子アクションでは View メソッドではなく PartialView メソッドを使ってビューを返します。View メソッドを使うと _Layout.cshtml に埋め込まれた形でレンダリングされてしまいます。

レンダリングされる部分ビューも作成します。今回は単純にコレクションをリスト表示するだけのビューです。

@model IEnumerable<string>

<h3>News</h3>
<ul>
@foreach (var item in Model)
{
    <li>@item</li>
}
</ul>

これで子アクションと部分ビューの準備が出来たので、セクションに表示するためのコードを書きます。Action と RenderAction のどちらでもいいのですが、今回は Action を使いました。

@section SideBar
{
    @Html.Action("News", "Module")
}

これでセクションと子アクションの準備が出来たので実行して確認してみます。

ちゃんとサイドバーに子アクションと部分ビューで指定した内容が出力されていることが分かりますね。このように @section を使うとメイン以外のコンテンツ出力、子アクションを使うと親アクションのコードを弄ることなくインライン出力することが出来ます。

ASP.NET MVC 3 でも高度なレイアウトをメンテナンス性を保ったまま実現できます。サンプルがあまりないのが残念ですが…。