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)
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> ...
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With