Enum DisplayName: шаблоны могут использоваться только с полевым доступом

Я знаю, что уже есть другие темы по этому поводу. Я их читаю. Вот что у меня есть:

namespace Books.Entities
{
    public enum Genre
    {
        [Display(Name = "Non Fiction")]
        NonFiction,
        Romance,
        Action,
        [Display(Name = "Science Fiction")]
        ScienceFiction
    }
}

Модель:

namespace Books.Entities
{
    public class Book
    {
        public int ID { get; set; }

        [Required]
        [StringLength(255)]
        public string Title  { get; set; }

        public Genre Category { get; set; }
    }
}

Затем, в представлении:

@foreach (var item in Model) {
<tr>
    <td>
        @Html.DisplayFor(modelItem => item.Title)
    </td>
    <td>
        @Html.DisplayFor(modelItem => item.Category)
    </td>
</tr>

Я думаю, что фреймворк будет использовать свойство DisplayName автоматически. Кажется странным, что это не так. Но что угодно. Пытаясь преодолеть это с помощью расширения (нашел это в другой теме по тому же вопросу)...

using System;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Reflection;

public static class EnumExtensions
{
    public static string GetDisplayName(this Enum enumValue)
    {
        return enumValue.GetType()
                    .GetMember(enumValue.ToString())
                    .First()
                    .GetCustomAttribute<DisplayAttribute>()
                    .GetName();
    }
}

Похоже, это должно работать, но когда я пытаюсь использовать это:

 @Html.DisplayFor(modelItem => item.Category.GetDispayName())

Я получаю эту ошибку:

{"Templates can be used only with field access, property access, single-dimension array index, or single-parameter custom indexer expressions."}  

2 ответа

Решение

Одна вещь, которую вы могли бы рассмотреть, это добавить DisplayTemplate для Enum и ваш @Html.DiplayFor() будет использовать это.

Если вы создаете папку в вашем ~/Views/Shared папка называется DisplayTemplates, добавьте новое представление с именем Enum.cshtml и добавьте этот код в представление

@model Enum
@{
    var display = Model.GetDisplayName();
}
@display

Тогда все, что вам нужно сделать, это использовать @Html.DisplayFor(modelItem => item.Category) в других ваших взглядах.

Кстати ваш GetDisplayName Код выдаст ошибку, если нет атрибута описания, так что вы можете использовать что-то вроде

public static string GetDisplayName(this Enum enumValue)
    {

        Type type = enumValue.GetType();
        string name = Enum.GetName(type, enumValue);
        if (name != null)
        {
            FieldInfo field = type.GetField(name);
            if (field != null)
            {
                DescriptionAttribute attr =
                       Attribute.GetCustomAttribute(field,
                         typeof(DescriptionAttribute)) as DescriptionAttribute;
                if (attr != null)
                {
                    return attr.Description;
                }
            }
        }
        return name;
    }

Хорошо, нашел пару способов обойти это. Во-первых, как предложил mxmissile, просто используйте:

@item.Category.GetDisplayName()

Оказывается, сообщение об ошибке говорит мне именно то, что мне нужно было знать. Я просто не понял, что @Html.DisplayFor() - это шаблон, и я не могу использовать его с расширением помощника.

Но лучшее решение оказалось тем, которое я нашел здесь:

http://www.codeproject.com/Articles/776908/Dealing-with-Enum-in-MVC

В этом решении автор предоставляет шаблон отображения, который работает по умолчанию для всех перечислений, без необходимости задавать GetDisplayName(). С этим решением оригинальный код работает просто отлично:

@Html.DisplayFor(modelItem => item.Category)

И более того, по умолчанию это будет работать по всем направлениям.

(ПРИМЕЧАНИЕ: все это предполагает, что вы используете MVC5.x)

Другие вопросы по тегам