Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Calling IEnumerable overload of DisplayNameFor [duplicate]

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)
like image 212
AaronLS Avatar asked Oct 17 '12 19:10

AaronLS


2 Answers

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> ... 
like image 92
franz Avatar answered Sep 22 '22 14:09

franz


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.

like image 21
Alan Macdonald Avatar answered Sep 24 '22 14:09

Alan Macdonald