Search code examples
c#asp.net-coreviewmodelasp.net-core-2.2

How can Razor page find the field in DisplayNameFor?


I'm surprised why the following table finds the names correctly.

@model IEnumerable<Member>
<table class="table">
  <thead>
    <tr>
      <th>
        @Html.DisplayNameFor(model => model.LastName)
      </th>
    <tr>
    ...

The model I've set is an array of type Member so the model has no property LastName. An element in the list does! Shouldn't it be

<th>
  @Html.DisplayNameFor(model => model.First().LastName)
</th>

I never noticed that until I changed my viewmodel to

public class IndexVm
{
  public IEnumerable<Member> Members { get; set; }
}

and tried to

<th>
  @Html.DisplayNameFor(model => model.Members.LastName)
</th>

This stopped working and when I investigated, I realized that I can see why. I can't understand how it could work previously, though...

  1. Can someone explain what's up with that?
  2. Is the below the only option given my new viewmodel?
  3. How is the computer supposed to know what to display if the list is empty?

    @Html.DisplayNameFor(model => model.Members.FirstOrDefault()?.LastName)

So confused...


Solution

  • The DisplayNameFor shows the name of the property or the string defined in the display attribute for the property.For

    @Html.DisplayNameFor(model => model.LastName)
    

    , it works since model has a type of Member not IEnumerable<Member> in the lambda expression.

    You could use

    @Html.DisplayNameFor(model => model.Members.FirstOrDefault().LastName)
    

    This still works even if FirstOrDefault() would return null since it uses metadata from lambda expressions internally, the LastName property itself is not accessed.

    If Members is list IList<Member>, you could also use Members[0]

    @Html.DisplayNameFor(model => model.Members[0].LastName)
    

    Refer to here and here.