DisplayAttribute によってフィールドに表示名が指定された列挙型の値を、View(Razor) で表示しようとしても表示されない。
HtmlHelper.DisplayFor メソッドを使用しても列挙値のフィールド名が表示されるだけで DisplayAttribute で指定した表示名を引っ張ってくれない。
いろいろ調べて、HtmlHelper の拡張メソッドを自作することで解決したのでメモ。
以下、前振りから。
モデルにあるプロパティが定義されてあって、そのプロパティに DisplayNameAttribute によって表示名称が取得されている場合、それを表示するのに HtmlHelper.DisplayNameFor メソッドを使用する。DisplayNameAttribute が設定されていなければプロパティ名がそのまま表示される。
たとえば以下のようにプロパティが定義されている場合。
[DisplayName("変数名1")] public string ParameterName1 { get; set; } [DisplayName("値1")] public string Value1 { get; set; } public string ParameterName2 { get; set; } public string Value2 { get; set; }
View(Razor) で以下のように書くと、
<dt> @Html.DisplayNameFor(model => model.ParameterName1) </dt> <dd> @Html.DisplayFor(model => model.ParameterName1) </dd> <dt> @Html.DisplayNameFor(model => model.Value1) </dt> <dd> @Html.DisplayFor(model => model.Value1) </dd> <dt> @Html.DisplayNameFor(model => model.ParameterName2) </dt> <dd> @Html.DisplayFor(model => model.ParameterName2) </dd> <dt> @Html.DisplayNameFor(model => model.Value2) </dt> <dd> @Html.DisplayFor(model => model.Value2) </dd>
表示はこんな感じに。
値を表示するときは HtmlHelper.DisplayFor メソッドを使用。
さて、このプロパティが以下のような列挙型で、
public enum ParameterType : int { [Display(Name = "固定値")] FixedValue = 0, [Display(Name = "漢字氏名")] UserName, [Display(Name = "メールアドレス")] MailAddress, [Display(Name = "年度")] Year, }
プロパティの定義が以下だった場合。
[DisplayName("変数名1")] public string ParameterName1 { get; set; } [DisplayName("値1")] public ParameterType Value1 { get; set; } public string ParameterName2 { get; set; } public ParameterType Value2 { get; set; }
表示は以下のようになってしまう。
普通、列挙値に DisplayAttribute を指定して表示名を指定しているわけなので、最初と同じように、
と表示して欲しい。
というわけで、HtmlHelper に拡張メソッド DisplayEnumFor を自作して解決。
public static IHtmlString DisplayEnumFor<TModel, TProp>(this HtmlHelper<TModel> html, Expression<Func<TModel, TProp>> expression) { var value = ModelMetadata.FromLambdaExpression(expression, html.ViewData).Model; if (!Enum.IsDefined(typeof(TProp), value)) { throw new ArgumentException(); } var field = value.GetType().GetField(value.ToString()); var attributes = field.GetCustomAttributes(typeof(DisplayAttribute), false) as DisplayAttribute[]; if (attributes == null || attributes.Length == 0) { return new HtmlString(value.ToString()); } else { return new HtmlString(attributes[0].Name); } }
値を取り出して、列挙型であることを確認して、FieldInfo オブジェクトを取得。
そこから DisplayAttribute を取得して Name プロパティを返す。
引数が列挙型のプロパティじゃなかった場合は ArgumentException を発生させ、DisplayAttribute が指定されていなかった場合は素直に列挙値を返す。
あとはこの拡張メソッドが定義された名前空間を Views フォルダ内の web.config に追記する。
<system.web.webPages.razor> <pages pageBaseType="System.Web.Mvc.WebViewPage"> <namespaces> <add namespace="System.Web.Mvc" /> <add namespace="System.Web.Mvc.Ajax" /> <add namespace="System.Web.Mvc.Html" /> <add namespace="System.Web.Optimization"/> <add namespace="System.Web.Routing" /> <add namespace="Sample" /> <add namespace="Sample.Extensions"/> </namespaces> </pages> </system.web.webPages.razor>
これで以下のように DisplayEnumFor メソッドを使用して列挙型のフィールドに DisplayAttribute で指定した表示名称が使える。
<dt> @Html.DisplayNameFor(model => model.ParameterName1) </dt> <dd> @Html.DisplayFor(model => model.ParameterName1) </dd> <dt> @Html.DisplayNameFor(model => model.Value1) </dt> <dd> @Html.DisplayEnumFor(model => model.Value1) </dd> <dt> @Html.DisplayNameFor(model => model.ParameterName2) </dt> <dd> @Html.DisplayFor(model => model.ParameterName2) </dd> <dt> @Html.DisplayNameFor(model => model.Value2) </dt> <dd> @Html.DisplayEnumFor(model => model.Value2) </dd>
0 件のコメント:
コメントを投稿