Application is an MVC3 application with RAZOR view engine.
Controller being used here is TestController. I am using Nested Views.
Base view(Item Listing) goes like this,
//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 Item
//Item.cshtml
@model Item
@Html.DisplayFor(x=>x.HeaderText)
@Html.DisplayFor(x=>x, "ItemDetails")
And here is the view for Item Details
//ItemDetails.cshtml
@model Item
@Html.DisplayFor(x=>x.Description)
So, I am trying to pass forward model from ITEM template to ITEMDETAILS template. ItemDetails.cshtml is placed under "Views\Test\DisplayTemplates". Infact i have tried placing it under folders "Views\Shared" as well as "Views\Shared\DisplayTemplates". But View engine seems just not to picking it up.
However Microsoft documentation here states that view engine does look in Controller\DisplayTemplates folder to fetch the VIEW using TemplateName used.
This appears to be the intended behaviour for Display/EditorTemplates, presumably to prevent accidental infinite recursion in custom display templates, such as doing (in Item.cshtml
):
@model Item
@Html.DisplayFor(x => x)
...which would infinitely display the Item.cshtml
DisplayTemplate.
Obviously in your example you're passing the item/model to a different template, so it wouldn't cause infinite recursion. However, it still seems to get caught by the same safe-guard in the framework. Not really sure if it would be classified as a 'bug' or just 'by design'?
This is the check in the 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 the visited objects/models for parent templates. When you run:
@Html.DisplayFor(x => x.Items[i], new { RowPosition = i})
It renders your Item.cshtml
DisplayTemplate and adds the item/model to VisitedObjects
. This means when Item.cshtml
tries to display another child template with the same item/model:
@Html.DisplayFor(x => x, "ItemDetails")
The item/model is already in VisitedObjects
, so the if statement above returns true and instead of rendering ItemDetails.cshtml
it just silently returns/renders an empty string.
try using @Html.RenderPartial("ItemDetails", item)
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