書籍転載:ASP.NET MVC 5 実践プログラミング
テンプレート関連のビューヘルパー|テンプレートの標準の挙動[Razor]
「テンプレートヘルパー」とも呼ばれるDisplayFor/EditorForメソッドについて紹介。また、テンプレートヘルパーの標準的な挙動を確認する。書籍転載の15本目(基礎編「4-4-1」)。
書籍転載について
本コーナーは、秀和システム発行の書籍『ASP.NET MVC 5 実践プログラミング』の中から、特にBuild Insiderの読者に有用だと考えられる項目を編集部が選び、同社の許可を得て転載したものです。
『ASP.NET MVC 5 実践プログラミング』の詳細や購入は秀和システムのサイトや目次ページをご覧ください。
ご注意
本記事は、書籍の内容を改変することなく、そのまま転載したものです。このため用字用語の統一ルールなどはBuild Insiderのそれとは一致しません。あらかじめご了承ください。
4-4 テンプレート関連のビューヘルパー
DisplayFor/EditorForヘルパー*20は、言うなれば、モデル定義に応じて出力を自在に変化できるヘルパー。DisplayForヘルパーがデータの表示を、EditorForヘルパーがデータ編集(入力)項目の生成を、それぞれ担っています。
- *20 あらかじめ決められたテンプレートに基づいて、出力を決定することから、テンプレートヘルパーと総称する場合もあります。
「モデル定義に応じて」と言ってわかりにくければ、モデルに定義されているデータ型、あるいは、付随するメタ情報(属性)に応じて、適切な出力を生成する、と言い換えても良いかもしれません。(たとえば)プロパティの型がstring型であれば、EditorForメソッドは標準のテキストボックス(<input type="text">要素)を、bool型であればチェックボックス(<input type="checkbox">要素)を、それぞれ出力します。
モデルの状態をヘルパーが自動的に認識してくれるわけです。このような性質から、テンプレートヘルパーには、以下のようなメリットがあります。
- ビューが、プロパティの型/メタ情報を意識しなくても良い
- モデル(型/メタ情報)の変更がビューに影響しにくい
- 同じ型(メタ情報)であれば同じ出力を生成するので、出力に一貫性を持たせやすい
モデルをもとにデータを入出力するならば、まずはTextBoxFor/CheckBoxForなど個別のヘルパーではなく、テンプレートヘルパーを優先して利用するのが望ましいでしょう。前章でも見たように、Scaffolding機能で自動生成されたコードもテンプレートヘルパーで記述されています。
4-4-1 テンプレートの標準の挙動
まずは、テンプレートヘルパーの標準的な挙動を確認してみましょう。以下で作成するのは、Articlesテーブル(記事情報)を参照/編集するためのごくシンプルなサンプルです。
1データモデルを準備する
テンプレートヘルパーを利用するには、まず、データモデルに対して適切なデータ型、メタ情報(属性)を定義しておく必要があります。以下は、記事情報を表すArticleエンティティと、これに付随するコメント情報を表したCommentエンティティの例です。
エンティティ間のリレーションシップを表す方法については、5-1-1項(※転載対象外)にて改めて触れます。ここでは、Article/Commentエンティティが1:nの関係にあるとだけ理解しておいてください。
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
namespace MvcView.Models
{
public class Article
{
public int Id { get; set; }
[DisplayName("URL")]
[DataType(DataType.Url)]
public string Url { get; set; }
[DisplayName(" タイトル ")]
public string Title { get; set; }
[DisplayName(" カテゴリー ")]
public CategoryEnum Category { get; set; }
[DisplayName(" 概要 ")]
[DataType(DataType.MultilineText)]
public string Description { get; set; }
[DisplayName(" ビュー数 ")]
public int Viewcount { get; set; }
[DisplayName(" 公開日 ")]
[DisplayFormat(DataFormatString = "{0:yyyy年MM月dd日}")]
public DateTime Published { get; set; }
[DisplayName(" 公開済 ")]
public bool Released { get; set; }
[DisplayName(" コメント ")]
public virtual ICollection<Comment> Comments { get; set; }
}
}
|
using System;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
namespace MvcView.Models
{
[DisplayColumn("Body")]
public class Comment
{
public int Id { get; set; }
[DisplayName(" 氏名 ")]
public string Name { get; set; }
[DisplayName(" コメント ")]
public string Body { get; set; }
[DisplayName(" 更新日 ")]
public DateTime Updated { get; set; }
public int? ArticleId { get; set; }
[DisplayName(" 記事 ")]
public virtual Article Article { get; set; }
}
}
|
テンプレートヘルパーに関連するメタ情報(属性)には、以下のようなものがあります。
概要 | 属性 | ||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|
DataType(type) | 追加的な型情報(具体的な設定値は表4-5を参照) | ||||||||||
Display(props) | 表示に関わる諸情報(利用可能なプロパティは以下)
|
||||||||||
DisplayFormat(props) | 表示のための書式情報(利用可能なプロパティは以下)
|
||||||||||
UIHint(view) | プロパティ値の表示/編集に利用するテンプレート(4-4-2項) | ||||||||||
DisplayColumn(column) | 外部キーで関連付いた参照先テーブルの表示列 |
DataType属性は、標準のint、stringのような型では表しきれない意味的な型情報を表します。たとえばArticleエンティティのUrlプロパティであれば、DataType属性にUrlが設定されているので、EditorForメソッドは<input type="url">要素を出力します。
その他、データ型、メタ情報によって、どのような出力が生成されるのかを、以下にまとめます。
ヘルパー | データ型/メタ情報 | 出力 (結果) |
---|---|---|
DisplayFor | bool型 | チェックボックス(Nullable型の場合は選択ボックス) |
DataType(EmailAddress) | メールリンク(<a href="mailto:~">要素) | |
DataType(Url) | ハイパーリンク(<a href="~">要素) | |
DataType(Html) | 値をエンコードせずに出力 | |
ICollection型 | 参照先テーブルの列を列挙*21 | |
EditorFor | bool型 | チェックボックス(Nullable型の場合は選択ボックス) |
int/long型 | 数値入力ボックス(<input type="number">要素) | |
列挙型 | 選択ボックス(<select>要素) | |
DataType(Date) | 日付入力ボックス(<input type="date">要素) | |
DataType(DateTime) | 日時入力ボックス(<input type="datetime">要素) | |
DataType(EmailAddress) | メールアドレス入力ボックス(<input type="email">要素) | |
DataType(MultilineText) | テキストエリア(<textarea>要素) | |
DataType(Password) | パスワード入力ボックス(<input type="password">要素) | |
DataType(PhoneNumber) | 電話番号入力ボックス(<input type="tel">要素) | |
DataType(Time) | 時刻入力ボックス(<input type="time">要素) | |
DataType(Url) | URL入力ボックス(<input type="url">要素) | |
UIHint(HiddenInput) | 隠しフィールド |
- *21 表示すべき列は、DisplayColumn属性で指定します。
2Scaffolding機能でアプリケーションを作成する
データモデルを用意できたら、ArticleエンティティをもとにアプリケーションをScaffoldしてみましょう。手順は3-1節(※転載対象外)を参照いただくとして、最低限、[コントローラーの追加]ダイアログでの入力例だけを示しておきます。
項目 | 設定値 |
---|---|
モデルクラス | Article(MvcView.Models) |
データコンテキストクラス | MvcViewContext(MvcView.Models)*22 |
ビューの生成 | チェック |
レイアウトページの使用 | チェック |
コントローラー名 | ArticlesController |
- *22 コンテキストクラスについては2-4-3項(※転載対象外)で解説していますので、本項では割愛します。具体的なコードは配布サンプルを参照してください。
ただし、ICollection型のCommentsプロパティは、Scaffolding機能では自動的には組み込まれませんので、以下のように手動で追加します(追記は太字部分)。
@model MvcView.Models.Article
... 中略 ...
<div>
<h4>Article</h4>
<hr />
<dl class="dl-horizontal">
... 中略 ...
<dt>
@Html.DisplayNameFor(model => model.Comments)
</dt>
<dd>
@Html.DisplayFor(model => model.Comments)
</dd>
</dl>
</div>
|
3サンプルを実行する
Scaffoldしたアプリケーションを実行し、詳細画面、編集画面を確認してみましょう。データはイニシャライザーで投入しても、画面から手入力しても構いません*23。
- *23 配布サンプルではイニシャライザーを提供していますので、デフォルトで最低限のデータが用意されています。
実行結果は、できればHTML5のフォーム要素に比較的よく対応しているChromeを利用することをお勧めします。
すると、詳細画面では、
- Urlプロパティがリンクとして表示されること
- Publishedプロパティが「yyyy年MM月dd日」の形式で整形されていること
- Releasedプロパティは読み取り専用のチェックボックスとして表示されること
- Commentsプロパティは、CommentエンティティのDisplayColumn属性で指定されたBodyプロパティの列挙として表示されること
を、編集画面では、
- Categoryプロパティが選択ボックス(列挙体のメンバーを一覧)として表示されること
- Descriptionプロパティがテキストエリアとして表示されること
- Viewcountプロパティが数値入力ボックスとして表示されること
- Publishedプロパティが日付入力ボックスとして表示されること*24
- Releasedプロパティがチェックボックスとして表示されること
を、それぞれ確認してみましょう。
- *24 執筆時点のChromeでは、単なるテキストボックスとして表示されます。
【Note】LabelFor/DisplayNameForメソッド
モデル(プロパティ)の定義に応じて、プロパティの表示名を表示するLabelFor/DisplayNameForメソッドもあります。LabelForメソッドは表示名をラベルに整形して、DisplayNameForメソッドはそのまま、それぞれ表示します。
詳しくは、3-2-1、3-4-1項など(※いずれも転載対象外)でも触れていますので、合わせて参照してください。
※以下では、本稿の前後を合わせて5回分(第13回~第17回)のみ表示しています。
連載の全タイトルを参照するには、[この記事の連載 INDEX]を参照してください。
13. アプリケーションルートからの絶対パスを生成する - Url.Content/Action/RouteUrlメソッド[Razor]
リソース指定は、相対パスよりも、アプリケーションルートからの絶対パスの方がよい。そのような絶対パスを生成するUrlオブジェクトの機能を解説。書籍転載の13本目(基礎編「4-3-3」)。
14. HTMLエンコードを無効にする - Html.Rawメソッド[Razor]
デフォルトで実行されるHTML予約文字のエスケープ処理を無効にして生のままHTMLコードを出力するためのHtml.Rawメソッドについて解説。書籍転載の14本目(基礎編「4-3-4」)。
15. 【現在、表示中】≫ テンプレート関連のビューヘルパー|テンプレートの標準の挙動[Razor]
「テンプレートヘルパー」とも呼ばれるDisplayFor/EditorForメソッドについて紹介。また、テンプレートヘルパーの標準的な挙動を確認する。書籍転載の15本目(基礎編「4-4-1」)。
16. テンプレートのカスタマイズ|テンプレートを決定する方法[Razor]
テンプレートヘルパーでは、特定のデータ型/メタ情報に応じた独自のテンプレートを用意して、独自の出力を生成することもできる。その方法を解説する。書籍転載の16本目(基礎編「4-4-2」「4-4-3」)。
17. モデル単位にテンプレートを決定する - DisplayForModel/EditorForModelメソッド[Razor]
プロパティ単位ではなくモデル単位でHTMLコードを出力するDisplayForModel/EditorForModelメソッドについて解説。また、そのテンプレートを自作する方法を説明する。書籍転載の17本目(基礎編「4-4-4」)。