I have this line in my view
@(Html.DisplayFor(m => m.DaysOfWeek, "_CourseTableDayOfWeek"))
where m.DaysOfWeek
is a IEnumerable<DateTime>
.
There is the content 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 item passed into the dictionary is of type 'System.Collections.Generic.List`1[System.DateTime]
', but this dictionary requires a model item of type 'System.DateTime
'.
If I refer to the following post:
https://stackoverflow.com/a/5652524/277067
The DisplayFor
should be looping through the IEnumerable and display the template for each item, shouldn't it?
It's not looping because you have specified a name for the display template as second argument of the DisplayFor
helper (_CourseTableDayOfWeek
).
It loops only when you rely on conventions 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>
Once you specify a custom name for the display template (either as second argument of the DisplayFor helper or as [UIHint]
attribute) it will no longer loop for collection properties and the template will simply be passed the IEnumerable<T>
as model.
It's confusing but that's how it is. I don't like it either.
This seems like a bug. Html Helper classes are easy to extend, although after looking at the MVC source, looking for the bug, I gave up and just leveraged the premise that templates work for an individual item, so I wrote an HtmlHelper extension that wraps it for you. I took out the lambda expression for my own simplicity, but you can easily go back to that. This example is just for a list of strings.
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 usage looks like:
@Html.DisplayForList(Model.Organizations, "infoBtn")
A minor tweak to allow this to Dan's solution to be a little more generic:
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
, on the IEnumerable<T>
property.
public class MyModel
{
[FilterUIHint("_CourseTableDayOfWeek")]
public IEnumerable<DateTime> DaysOfWeek { get; set; }
}
No need for anything else.
@Html.DisplayFor(m => m.DaysOfWeek)
This now displays an "_CourseTableDayOfWeek"
EditorTemplate for each DateTime
in DaysOfWeek
.