问题
This works for grabbing the headers(NOT VALUES):
@model IEnumerable<SomeModel>
...
<th>@Html.DisplayNameFor(m => m.SomeModelProperty)</th>
Which if SomeModelProperty were:
[Display(Name = "An Excellent Header")]
SomeModelProperty { get; set; }
Then it would display "An Excellent Header" in the header th
element.
You would think this wouldn't work because the model is IEnumerable, which wouldn't have a m.SomeModelProperty, but it works because HtmlHelper has a HtmlHelper<IEnumerable<TModel>>
such that the parameter of the lambda is TModel
, not IEnumerable<TModel>
. Since this just uses metadata, there is no need for an item from the collection. (Although intellisense on m.
will lie to you and make you think it's a collection). I'm not sure when this cool overload was added, but is quite handy for Index.cshtml and does away with funky things like @Html.DisplayNameFor(m => @Model.FirstOrDefault().SomeModelProperty)
which I want to avoid.
http://msdn.microsoft.com/en-us/library/hh833697(v=vs.108).aspx
However, I can't figure out how to get this to work when my model is not IEnumerable, but instead contains IEnumerable as a property, such as:
public class SomeList
{
public List<SomeModel> SomeModels { get; set; }
public int Page { get; set; }
public DateTime CurrentAsOf { get; set; }
}
I was hoping to be explicit with the generic type parameters, but I think the type parameters are specified by the engine that trickles down from the HtmlHelper created with the page. Can I declare a new HtmlHelper in the page, or somehow specify the type parameters explicitly?
Index.cshtml:
@model SomeList
//No idea how to do this:
@Html.DisplayNameFor<IEnumerable<SomeModel>>(m => m.SomeModelProperty)
回答1:
Another similar workaround that works even if there are no rows could be:
...
@{var dummy = Model.FirstOrDefault(); }
<tr>
<th>
@Html.DisplayNameFor(model => dummy.SomeModelProperty)
</th>
...
回答2:
I have exactly the same issue because I am using ViewModels so I have a ViewModel with an IEnumerable of actual objects as a property.
I did come across this post where if you check the answer the guy has created his own HTMLHelper for it to solve this issue http://forums.asp.net/t/1783733.aspx. His version is:
public static MvcHtmlString DisplayColumnNameFor<TModel, TClass, TProperty>(
this HtmlHelper<TModel> helper, IEnumerable<TClass> model,
Expression<Func<TClass, TProperty>> expression)
{
var name = ExpressionHelper.GetExpressionText(expression);
name = helper.ViewContext.ViewData.TemplateInfo.GetFullHtmlFieldName(name);
var metadata = ModelMetadataProviders.Current.GetMetadataForProperty(
() => Activator.CreateInstance<TClass>(), typeof(TClass), name);
return new MvcHtmlString(metadata.DisplayName);
}
You have to pass two arguments enumeration and expression rather than the normal just expression so you may prefer @franz answer. I can't see there being anyway round having to pass 2 arguments since it needs to know which property of the view model you are applying the expression to.
来源:https://stackoverflow.com/questions/12941465/calling-ienumerable-overload-of-displaynamefor