Почему мой DisplayFor не зацикливается на моем IEnumerable <DateTime>?

У меня есть эта строка в моем представлении

@(Html.DisplayFor(m => m.DaysOfWeek, "_CourseTableDayOfWeek"))

где m.DaysOfWeek - IEnumerable<DateTime>.

Содержимое _CourseTableDayOfWeek.cshtml:

@model DateTime
@{
    ViewBag.Title = "CourseTableDayOfWeek";
}
<th>
    @System.Globalization.CultureInfo.CurrentCulture.DateTimeFormat.DayNames[(int) Model.DayOfWeek]
    <span class="dateString">Model.ToString("G")</span>
</th>

И я получаю следующую ошибку:

Элемент модели, переданный в словарь, имеет тип "System.Collections.Generic.List`1[System.DateTime]", но для этого словаря требуется элемент модели типа "System.DateTime".

Если я ссылаюсь на следующее сообщение:

qaru.site/info/125100/...

DisplayFor должен зацикливаться на IEnumerable и отображать шаблон для каждого элемента, не так ли?

Ответ 1

Он не зацикливается, потому что вы указали имя для шаблона отображения в качестве второго аргумента хелпера DisplayFor (_CourseTableDayOfWeek).

Он зацикливается только тогда, когда вы полагаетесь на соглашения, т.е.

@Html.DisplayFor(m => m.DaysOfWeek)

а затем внутри ~/Views/Shared/DisplayTemplates/DateTime.cshtml:

@model DateTime
@{
    ViewBag.Title = "CourseTableDayOfWeek";
}
<th>
    @System.Globalization.CultureInfo.CurrentCulture.DateTimeFormat.DayNames[(int) Model.DayOfWeek]
    <span class="dateString">Model.ToString("G")</span>
</th>

После того, как вы укажете собственное имя для шаблона отображения (либо в качестве второго аргумента для вспомогательного элемента DisplayFor, либо как атрибут [UIHint]), он больше не будет зацикливаться на свойствах коллекции, и шаблон будет просто передан как IEnumerable<T> как модель,

Это сбивает с толку, но так оно и есть. Мне тоже это не нравится.

Ответ 2

Это похоже на ошибку. Классы Html Helper легко расширяются, хотя, посмотрев на источник MVC, ища ошибку, я отказался и просто использовал предположение, что шаблоны работают для отдельного элемента, поэтому я написал расширение HtmlHelper, которое завершает его для вас. Я вытащил лямбда-выражение для своей простоты, но вы можете легко вернуться к этому. Этот пример предназначен только для списка строк.

    public static class DisplayTextListExtension
{
    public static MvcHtmlString DisplayForList<TModel>(this HtmlHelper<TModel> html, IEnumerable<string> model, string templateName)
    {
        var tempResult = new StringBuilder();

        foreach (var item in model)
        {
            tempResult.Append(html.DisplayFor(m => item, templateName));
        }

        return MvcHtmlString.Create(tempResult.ToString());
    }
}

Тогда фактическое использование выглядит следующим образом:

                                @Html.DisplayForList(Model.Organizations, "infoBtn")

Ответ 3

Небольшой твик, позволяющий этому решению Dan быть немного более общим:

public static class DisplayTextListExtension
    {
        public static MvcHtmlString DisplayForList<TModel, 
EModel>(this HtmlHelper<TModel> html, IEnumerable<EModel> model, string templateName)
        {
            var tempResult = new StringBuilder();

            foreach (var item in model)
            {
                tempResult.Append(html.DisplayFor(m => item, templateName));
            }

            return MvcHtmlString.Create(tempResult.ToString());
        }
    }

Ответ 4

Используйте FilterUIHint вместо обычного UIHint в свойстве IEnumerable<T>.

public class MyModel
{
    [FilterUIHint("_CourseTableDayOfWeek")]
    public IEnumerable<DateTime> DaysOfWeek { get; set; }
}

Не нужно ничего другого.

@Html.DisplayFor(m => m.DaysOfWeek)

Теперь отображается "_CourseTableDayOfWeek" EditorTemplate для каждого DateTime в DaysOfWeek.