0

I found this Related Topic, but it failed to answer my question.

When automatically creating a strongly typed view, lets say with a List scaffolding template, I will get something roughly like this:

@model IEnumerable<Test.Models.abc>
<table>
    <tr>
    <th>
        @Html.DisplayNameFor(model => model.ID)
    </th>
</tr>

@foreach (var item in Model) {
<tr>
    <td>
        @Html.DisplayFor(modelItem => item.ID)
    </td>
</tr>
}
</table>

I understand @Html.DisplayNameFor(model => model.ID) completely, but not @Html.DisplayFor(modelItem => item.ID).

What is the purpose of modelItem? Replacing it with any arbitrary text will result in a functional web page. It seems that modelItem is just a throwaway word. I guess my real question is why doesn't this work?

@Html.DisplayFor(item => item.ID)

Edit

A good point was brought up in the comments. It seems you are also able to change model to anything so long as you change it on both sides of the lambda expression:

@Html.DisplayNameFor(abc => abc.ID)

A side question would be: How does the @model statement at the top affect the functions below? I had previously thought model referenced the @model expression in order to figure out the display name via the class, but the page still works after the mentioned changes.

Community
  • 1
  • 1
Jeff
  • 2,283
  • 9
  • 32
  • 50
  • 1
    Why do you understand the first but not the second? You can replace `model` with any word as well. – GSerg Jan 09 '13 at 20:30
  • In that case you need to change both instances of `model` to the identical thing. So I guess I don't understand it completely. I was under the impression that `model` references the first line which tells it which class/model to use. Care to explain? – Jeff Jan 09 '13 at 20:46
  • 1
    No, `model` means nothing because C# is case-sensitive and the actual model is `Model`. In your first lambda the return value depends on the lambda argument. (The compiler knows the argument is of your `Model` type. You don't actually pass your `Model`, you pass instructions -- which property of `Model` to take.) Which is why it must be same variable name on left and right. In your second lambda your wanted result does not depend on the lambda argument, but you still have to pass an argument. Which is why its name is not important, it just gets discarded. – GSerg Jan 09 '13 at 20:58
  • +1 for the great response. You should consider submitting an answer. – Jeff Jan 09 '13 at 21:04

2 Answers2

1

It does not work because item is already declared in outer scope in foreach.

@foreach (var item in Model).

The reason why modelItem lambda is not used is because of that iteration of IEnumerable. If there would be Test.Models.abc as model instead of IEnumerable, then would that lambda does matter and the code of DisplayFor would change to @Html.DisplayFor(m => m.ItemId).

Update

@model IEnumerable<Test.Models.abc> just declares that this view is strongly typed, with type of IEnumerable<Test.Models.abc> - in your case. That means that view property this.Model (not model) is of type IEnumerable<Test.Models.abc> - and also that model of that type should passed into this view. model in example above is just expression variable - it has scope just for that expression. You can change it's name to any unprotected legal variable name that was not already used in outer scope (that's why it should not be named Model, because it would hide the Model property already declared in view).

mipe34
  • 5,596
  • 3
  • 26
  • 38
0

item is already a variable defined in an outer scope. You are capturing it as a closure, which is not ideal here. What your code should read is:

@Html.DisplayFor(modelItem => modelItem.ID)
jam40jeff
  • 2,576
  • 16
  • 14
  • Are you sure that this would work? `modelItem` here is an `IEnumerable` which definitely does not have property ID. Which is also reason why there is used variable `item` defined in that `foreach` iteration. – mipe34 Jan 09 '13 at 20:47
  • This actually doesn't work. The code I presented is working code – Jeff Jan 09 '13 at 20:50
  • The `IEnumerable` here is `Model`. `modelItem` is defined only within the lambda, so this solution should work just as any other solution presented (it is identical to the accepted solution of `@Html.DisplayFor(m => m.ItemId)`). – jam40jeff Jan 11 '13 at 16:48