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 件のコメント:
コメントを投稿