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

第6回 テンプレート機能でビュー開発を効率化

山田 祥寛(http://www.wings.msn.to/
2011/08/19
Page1 Page2 Page3

 前回は、ASP.NET MVC 3で搭載された新たなビュー・エンジン「Razor」と、ビュー開発で利用できる主なビュー・ヘルパーについて解説した。ASP.NET MVCでは、Webフォームのようなサーバ・コントロールこそ利用できないものの、ビュー・ヘルパーを活用することで、ビュー開発をかなりの程度まで効率化できる。

 今回も前回に引き続き、ビュー・ヘルパーの話題だ。前回扱えなかったビュー・ヘルパーとして、DisplayFor/EditorFor、DisplayForModel/EditorForModelヘルパーについて解説するとともに、記事後半では、ビュー・ヘルパーの自作についても扱う。

モデルを自動認識する高機能なビュー・ヘルパー − DisplayFor/EditorFor −

 DisplayFor/EditorForヘルパーは、いうなれば、モデル定義に応じて出力を自在に変化できるヘルパーだ。DisplayForヘルパーはデータ表示を、EditorForヘルパーはデータ編集(入力)項目の生成を担う。

 “モデル定義に応じて”とは、もっといえば、モデルが持つプロパティのデータ型や付随するメタ情報に応じて、適切なタグを生成するということ。具体的には、(例えば)プロパティの型がstring型であればEditorForメソッドはテキストボックスを生成するが、bool型であればチェック・ボックス(または選択ボックス)を生成する、といった具合だ。

 モデルの状態をヘルパーが自動認識してくれるため、モデルの変更がビューに影響を及ぼさない(及ぼしにくい)のがDisplayFor/EditorForメソッドのよいところである。スキャフォールディング機能が自動生成するビュー・テンプレートも、DetailsFor/EditorForヘルパーにより記述されている。

■DisplayFor/EditorForヘルパーの基本的な挙動

 概要だけでは分かりにくいと思うので、まずは、DisplayFor/EditorForメソッドの標準的な動きを見てみよう。

 エンティティとしては、あらかじめ以下のようなMember/Messageエンティティを、また、対応するコンテキスト・クラスも定義しておこう(また、接続設定として、第2回のリスト4のようなコードが定義されているものとする)。

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using System.Web.Mvc;

namespace MvcTemplate.Models
{
  public class Member
  {
    public int MemberId { get; set; } // メンバーコード(主キー)

    [DisplayName("名前")]
    public string Name { get; set; } // 名前

    [DisplayName("パスワード")]
    [DataType(DataType.Password)]
    public string Password { get; set; } // パスワード

    [DisplayName("誕生日")]
    [DisplayFormat(DataFormatString="{0:yyyy年MM月dd日}")]
    public DateTime Birth { get; set; } // 誕生日

    [DisplayName("メールアドレス")]
    [DataType(DataType.EmailAddress)]
    public string Email { get; set; } // メール・アドレス

    [DisplayName("URL")]
    [DataType(DataType.Url)]
    public string Url { get; set; } // URL

    [DisplayName("紹介文")]
    [DataType(DataType.MultilineText)]
    public string Info { get; set; } // 詳細情報

    [DisplayName("メッセージ")]
    public virtual ICollection<Message> Messages { get; set; } // メッセージ
  }
}
Imports System.ComponentModel
Imports System.ComponentModel.DataAnnotations

Public Class Member
  Public Property MemberId As Integer ' メンバーコード(主キー)

  <DisplayName("名前")>
  Public Property Name As String ' 名前

  <DisplayName("パスワード")>
  <DataType(DataType.Password)>
  Public Property Password As String ' パスワード

  <DisplayName("誕生日")>
  <DisplayFormat(DataFormatString:="{0:yyyy年MM月dd日}")>
  Public Property Birth As DateTime ' 誕生日

  <DisplayName("メールアドレス")>
  <DataType(DataType.EmailAddress)>
  Public Property Email As String ' メール・アドレス

  <DisplayName("URL")>
  <DataType(DataType.Url)>
  Public Property Url As String ' URL

  <DisplayName("紹介文")>
  <DataType(DataType.MultilineText)>
  Public Property Info As String ' 詳細情報

  <DisplayName("メッセージ")>
  Public Overridable Property Messages As ICollection(Of Message) ' メッセージ

End Class
リスト1 メンバ情報を表すMemberエンティティ(上:Member.cs、下:Member.vb)

using System.ComponentModel.DataAnnotations;

namespace MvcTemplate.Models
{
  [DisplayColumn("Body")]
  public class Message
  {
    public int MessageId { get; set; } // メッセージID(主キー)

    public string Body { get; set; } // メッセージ本体
  }
}
Imports System.ComponentModel.DataAnnotations

<DisplayColumn("Body")>
Public Class Message

  Public Property MessageId As Integer ' メッセージID(主キー)

  Public Property Body As String ' メッセージ本体

End Class
リスト2 メンバに対するメッセージ情報を表すMessageエンティティ(上:Message.cs、下:Message.vb)

using System.Data.Entity;

namespace MvcTemplate.Models
{
  public class MyMvcContext : DbContext
  {
    public DbSet<Member> Members { get; set; }
    public DbSet<Message> Messages { get; set; }
  }
}
Imports System.Data.Entity

Public Class MyMvcContext : Inherits DbContext
  Public Property Members As DbSet(Of Member)
  Public Property Messages As DbSet(Of Message)
End Class
リスト3 Member、Messageエンティティを管理するコンテキスト・クラス(上:MyMvcContext.cs、下:MyMvcContext.vb)

 冒頭で述べたように、DisplayFor/EditorForヘルパーは、エンティティ(プロパティ)のデータ型、メタ情報によって出力を変化させる。従って、エンティティ定義に際しても適切なメタ情報(属性)を定義しておくことは重要だ。以下に、DisplayFor/EditorForメソッドに関係する主な属性をまとめておく。

属性 概要
DataType(type) 追加的な型情報(引数typeはMultilineText、EmailAddress、Url、Passwordなど)
DisplayFormat(props) データ・フィールドを表示するための書式を指定

プロパティ 概要
ApplyFormatInEditMode 編集モード時に書式文字列を適用するか
ConvertEmptyStringToNull 空文字列をNothing/nullに自動変換するか
DataFormatString 書式文字列
NullDisplayText 値がNothing/nullのときの表示テキスト
指定可能な書式
UIHint(view) プロパティ値の表示/編集に使用するビューを指定
DisplayColumn(column) 外部キーで関連付けられた参照先テーブルの列を指定
表1 DisplayFor/EditorForヘルパーに関係する主な属性

 例えば、MemberエンティティのPasswordプロパティであれば、DataType属性によってPasswordが設定されているので、EditorForメソッドはパスワード入力ボックス(=「<input type="password" />」というコード)を出力する。

 具体的に、それぞれの型、メタ情報によって、どのような出力が生成されるかについては、以下の表も参考にしていただきたい。

コントロール 型/メタ情報 生成される出力
DisplayFor bool型 チェック・ボックス(Nullable型の場合は選択ボックス)
ICollection型 参照先テーブルの列(表示列はDisplayColumn属性で指定)を列挙
DataType(EmailAddress) メール・リンク(<a href="mailto:〜">email</a>)
DataType(Url) ハイパーリンク(<a href="URL">URL</a>)
EditorFor bool型 チェック・ボックス(Nullable型の場合は選択ボックス)
DataType(Password) パスワード入力ボックス
DataType(MultilineText) テキストエリア
UIHint(HiddenInput) 隠しフィールド
表2 データ型/メタ情報によるDisplayFor/EditorForヘルパーの出力

 このようなMember/Messageエンティティを基にScaffold(スキャフォールド)したアプリケーションのビュー(Details.cshtmlのみ抜粋)と、その実行画面が以下だ。ただし、ICollection型のMessagesプロパティはスキャフォールディング機能では自動的に組み込まれないので、手動で追加している。

 なお、データは適宜、イニシャライザ機能を使って、もしくは、Visual Studioのデータ・シートから手動で追加しておくこと。

@model MvcTemplate.Models.Member

@{
  ViewBag.Title = "Details";
}

<h2>Details</h2>

<fieldset>
  <legend>Member</legend>

  <div class="display-label">Name</div>
  <div class="display-field">
    @Html.DisplayFor(model => model.Name)
  </div>


  ……中略……

  <div class="display-label">Messages</div>
  <div class="display-field">
    @Html.DisplayFor(model => model.Messages)
  </div>

</fieldset>
<p>
  @Html.ActionLink("Edit", "Edit", new { id=Model.MemberId }) |
  @Html.ActionLink("Back to List", "Index")
</p>
@ModelType MvcTemplate.Member

@Code
  ViewData("Title") = "Details"
End Code

<h2>Details</h2>

<fieldset>
  <legend>Member</legend>

  <div class="display-label">Name</div>
  <div class="display-field">
      @Html.DisplayFor(Function(model) model.Name)
  </div>

  ……中略……

  <div class="display-label">Messages</div>
  <div class="display-field">
      @Html.DisplayFor(Function(model) model.Messages)
  </div>

</fieldset>
<p>
  @Html.ActionLink("Edit", "Edit", New With {.id = Model.MemberId}) |
  @Html.ActionLink("Back to List", "Index")
</p>
リスト4 スキャフォールディング機能で自動生成された詳細画面のビュー・テンプレート(上:Details.cshtml、下:Details.vbhtml)
MembersControllerと、付随するビュー・テンプレートをScaffolding機能で自動生成。Messagesプロパティ(太字部分)のみ手動で書き足している。





図1 データの編集(上)/詳細画面(下)

 なるほど、Email/Urlなどのプロパティ値がハイパーリンクとして表示されていること、Birthプロパティが指定された書式で整形されていること、そして、Password/Infoプロパティの入力要素がそれぞれパスワード入力ボックスや複数行のテキストエリアとして出力されていることが、それぞれ確認できるはずだ。また、ICollection型のMessagesプロパティは、MessageエンティティでDisplayColumn属性として定義されたBodyプロパティの値が列挙されている点にも注目してほしい。

 

 INDEX
  ASP.NET MVC入門【バージョン3対応】
  第6回 テンプレート機能でビュー開発を効率化
  1.モデルを自動認識する高機能なビュー・ヘルパー(DisplayFor/EditorFor)
    2.独自の表示/編集テンプレートを準備する/モデル単位にテンプレートを適用
    3.ビュー・ヘルパーの自作/拡張メソッドとしてビュー・ヘルパーを定義
 
インデックス・ページヘ  「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 記事ランキング

本日 月間