技術日記
ASP.NET MVC 3でCRUDするときのHtmlHelper用テンプレートEdit

CRUD機能を自動生成するとビュー内で使われている、HtmlHelperのEditorForメソッド。モデルオブジェクトから各要素の型や名前を取得して、妥当な編集用フォームタグを生成してくれるのはいいんだけど、気軽にカスタマイズさせてくれないようだ。

たとえば、テキストの分量によってinput type="text"にHTML属性を追加してsize="80"とかしたり、長文テキストが入るからtextareaに差し替えようと思っても、メソッドにパラメータを追加して何とかするような方法は用意されていない。

表示をカスタマイズしたければ別途テンプレートファイルを用意して、それを使ってレンダリングするようにしてやらなければならない。

HtmlHelper.EditorForメソッドの中の、

[sourcecode language="c#"]
public static MvcHtmlString EditorFor(
  this HtmlHelper html,
  Expression> expression,
  string templateName
)
[/sourcecode]
みたいにtemplateNameパラメータをシグニチャに持つタイプ。このテンプレート関連の仕様が今ひとつわからないので調査。

EditorForModel メソッド (HtmlHelper, String)によれば、まずテンプレートファイルの検索順序としては、

templateName パラメーターと名前が一致するテンプレートが、コントローラーの EditorTemplates フォルダーにある場合は、そのテンプレートが、モデルのレンダリングに使用されます。 コントローラーの EditorTemplates フォルダーにテンプレートが見つからない場合は、templateName パラメーターの名前と一致するテンプレートが Views\Shared\EditorTemplates フォルダーで検索されます。 テンプレートが見つからない場合は、既定のテンプレートが使用されます。
となっている。アプリケーション全体で共用したい場合は、Views\Shared\EditorTemplatesフォルダ内、各コントローラごとに同名のテンプレートを使い分けたい場合は各コントローラ用のViewフォルダ内(FooController.csで使うならばViews\Foo\EditorTemplatesフォルダ)に置くと。

さらに、モデルクラスのプロパティのデフォルトテンプレートを指定したければ、

[sourcecode language="c#"] [UIHint("FooTemplate")] public string FooProperty {get; set;} [/sourcecode]

なんて感じでUIHint属性をつけると、自動的にそのテンプレートが使われると書いてある。けど、元のモデルクラスがADO.NET Entity Frameworkで自動生成されたクラスの場合は、どうすればいいんだ?

普通に考えたら、自動生成されるpartial classで定義されるプロパティに、別ファイルでpartial classを定義して同名プロパティに属性を追加する方法、なんてなさそうだけど。実際やってみたら曖昧な二重定義扱いにされてコンパイルが通らないし。

と思ったら、チュートリアル: ASP.NET MVC でのテンプレート化されたヘルパーを使用したデータの表示というドキュメントを発見。その中の、

[sourcecode language="c#"]
using System.ComponentModel.DataAnnotations;
namespace MvcTmpHlprs {
  [MetadataType(typeof(ProductMD))]
  public partial class Product {
    public class ProductMD {
      public object SellStartDate { get; set; }
      [UIHint("rbDate")]
      public object SellEndDate { get; set; }
      [DataType(DataType.Date)]
      public object DiscontinuedDate { get; set; }
      [ScaffoldColumn(false)]
      public object ModifiedDate { get; set; }
      [ScaffoldColumn(false)]
      public object rowguid { get; set; }
      [ScaffoldColumn(false)]
      public object ThumbnailPhotoFileName { get; set; }
    }
  }
}
[/sourcecode]
というサンプルコードが肝。

ADO.NET Entiry Frameworkで自動生成されたpatial class(サンプルではProduct)にMetadataType(typeof(メタデータを定義するクラス名))という属性をつけておき、メタデータを定義するクラス(サンプルコードではProductMD)では、追加属性をつけたいプロパティのシグニチャと追加する属性(UIHintとか)を定義する。すると、ほかのファイルで実装されているpartial classのプロパティに対して、別ファイルから属性を追加することができるようだ。うわー、気色悪い仕様。

でもまあこれで、ADO.NET Entity Frameworkで自動生成されたモデルクラス(テーブル)のプロパティ(カラム)に対して、その表示や編集に使用されるビューテンプレートを指定できるようになった。実装コードとしてはとても気色悪いし、可読性も悪すぎるけれども。

ちなみにテンプレートファイルの記述方法(特にモデルデータの受け渡し方法)も、今ひとつわからないのだが、基本的にはビューを追加する際に出てくるダイアログで、「厳密に型指定されたビューを作成する」&「部分ビューとして作成する」を選択し、「モデルクラス」として対応するプロパティの型を指定してやればいいんだろう。そうするとビュー内ではModelという名前でプロパティの値にアクセスできる。

Published At2011-11-18 20:09Updated At2011-11-18 20:09