Why doesn't my DisplayFor loop into my IEnumerable <DateTime>?
I have this line in my view
@(Html.DisplayFor(m => m.DaysOfWeek, "_CourseTableDayOfWeek")) where m.DaysOfWeek is IEnumerable<DateTime> .
Contents of _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> And I get the following error:
The model element passed to the dictionary is of type "
System.Collections.Generic.List`1[System.DateTime]", but this dictionary requires a model element of type "System.DateTime".
If I refer to the following message:
stack overflow
DisplayFor should loop around on IEnumerable and display a template for each element, right?
It does not loop because you specified the name for the display template as the second argument to the DisplayFor helper ( _CourseTableDayOfWeek ).
It loops only when you rely on agreements, i.e.
@Html.DisplayFor(m => m.DaysOfWeek) and then inside ~/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> After you specify your own name for the display template (either as the second argument to the DisplayFor helper element, or as the [UIHint] attribute), it will no longer loop over the properties of the collection, and the template will simply be passed as IEnumerable<T> as model,
This is confusing, but it is. I don't like that either.
This seems like a mistake. The Html Helper classes expand easily, although by looking at the MVC source and looking for an error, I refused and simply used the assumption that the templates work for a single element, so I wrote the HtmlHelper extension that completes it for you. I pulled out a lambda expression for my simplicity, but you can easily get back to that. This example is for a list of strings only.
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()); } } Then the actual use is as follows:
@Html.DisplayForList(Model.Organizations, "infoBtn") A small tweak that allows this Dan solution to be a little more general:
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()); } } Use FilterUIHint instead of the regular UIHint in the IEnumerable<T> property.
public class MyModel { [FilterUIHint("_CourseTableDayOfWeek")] public IEnumerable<DateTime> DaysOfWeek { get; set; } } Nothing else is needed.
@Html.DisplayFor(m => m.DaysOfWeek) Now the "_CourseTableDayOfWeek" EditorTemplate is displayed for each DateTime in DaysOfWeek .