Why doesn't RazorViewEngine pick up my DisplayTemplate?

The application is an MVC3 application with a RAZOR viewer.

The controller used here is TestController. I use Nested Views.

The basic view (list of items) is as follows:

//Listing.cshtml @model ItemsList @for (int i = 0; i < Model.Items.Count(); i++) { @Html.DisplayFor(x => x.Items[i], new { RowPosition = i}) } 

here is the template for the item

 //Item.cshtml @model Item @Html.DisplayFor(x=>x.HeaderText) @Html.DisplayFor(x=>x, "ItemDetails") 

And here is a view of item detailing

 //ItemDetails.cshtml @model Item @Html.DisplayFor(x=>x.Description) 

So, I'm trying to transfer the model from the ITEM template to the ITEMDETAILS template. ItemDetails.cshtml is placed in the "Views \ Test \ DisplayTemplates" section. Infact I tried placing it under the "Views \ Shared" folders as well as the "Views \ Shared \ DisplayTemplates". But the viewing mechanism doesn't seem to just pick it up.

However, the Microsoft documentation here claims that the viewer looks at the Controller \ DisplayTemplates folder to retrieve the VIEW using the used TemplateName.

+6
source share
3 answers

This seems to be the intended behavior for Display / EditorTemplates, supposedly to prevent accidental infinite recursion in custom display templates such as execution (in Item.cshtml ):

 @model Item @Html.DisplayFor(x => x) 

... which will display Item.cshtml DisplayTemplate endlessly.

Obviously, in your example, you are passing an element / model to another template, so this will not result in infinite recursion. However, he still seems to be in the same safe guard. Not quite sure if it will be classified as a “mistake” or just “by design”?

This is a check in DisplayFor / TemplateFor helper :

 // Normally this shouldn't happen, unless someone writes their own custom Object templates which // don't check to make sure that the object hasn't already been displayed object visitedObjectsKey = metadata.Model ?? metadata.RealModelType; if (html.ViewDataContainer.ViewData.TemplateInfo.VisitedObjects.Contains(visitedObjectsKey)) { // DDB #224750 return String.Empty; } 

ViewData.TemplateInfo.VisitedObjects stores visited objects / models for parent templates. At startup:

 @Html.DisplayFor(x => x.Items[i], new { RowPosition = i}) 

It displays your Item.cshtml DisplayTemplate and adds the item / model to VisitedObjects . This means that when Item.cshtml tries to display another child template with the same element / model:

 @Html.DisplayFor(x => x, "ItemDetails") 

The element / model is already in VisitedObjects , so the if statement returns true, and instead of rendering ItemDetails.cshtml it simply silently returns / displays an empty string.

+5
source

First, do not use a for loop. Display / EditorTemplates are capable of handling collections.

Secondly, what is an ItemsList? And how is this determined? If he just calls a certain type of collectibles then don't do it. Just have a List or something instead (unless you need special handling of the elements, in which case implement IEnumerable in your collection class). Then you will have ItemList.cshtml or just Item.cshtml if you convert it to a list

Also, your DisplayFor () in the main view is incorrect. you cannot pass html attributes to DisplayTemplates this way.

+1
source

try using @Html.RenderPartial("ItemDetails", item)

0
source

Source: https://habr.com/ru/post/914841/


All Articles