Как использовать DisplayTemplates на страницах ASP.Net Core Razor с наследованием модели?

Попытка заставить DisplayTemplates в ASP.Net Core 2.2 работать с классами, которые наследуются от базового класса, аналогично этому вопросу Как обрабатывать модель объекта с наследованием в представлении?

Principal DisplayTemplate используется для всех элементов в списке, что мне не хватает?

Модель страницы

public class IndexModel : PageModel
{
    public List<Principal> Principals { get; set; } = new List<Principal>();

    public void OnGet()
    {
        Principals.Add(new Principal { Id = 1, Name = "Principal 1" });
        Principals.Add(new UserPrincipal { Id = 1, Name = "User 1", Age = 30 });
        Principals.Add(new GroupPrincipal { Id = 1, Name = "Group 1", Members = 5 });
        Principals.Add(new UserPrincipal { Id = 1, Name = "User 2", Age = 40 });
        Principals.Add(new GroupPrincipal { Id = 1, Name = "Group 2", Members = 3 });
    }
}

public class Principal
{
    public int Id { get; set; }
    public string Name { get; set; }
}

public class UserPrincipal : Principal
{
    public int Age { get; set; }
}

public class GroupPrincipal : Principal
{
    public int Members { get; set; }
}

RazorPage

@page
@model IndexModel

@foreach(var principal in Model.Principals)
{
    @Html.DisplayFor(p => principal)
}

~/Pages/Shared/DisplayTemplates/Principal.cshtml

@model Principal
<div>
    <h4>Principal</h4>
    @Model.Name
</div>

~/Pages/Shared/DisplayTemplates/UserPrincipal.cshtml

@model UserPrincipal
<div>
    <h4>User</h4>
    @Model.Name, Age @Model.Age
</div>

~/Pages/Shared/DisplayTemplates/GroupPrincipal.cshtml

@model GroupPrincipal
<div>
    <h4>Group</h4>
    @Model.Name, Members @Model.Members
</div>


person mheptinstall    schedule 03.10.2019    source источник
comment
На своей странице бритвы вы пробовали @Html.DisplayFor(principal => Principal)?   -  person daremachine    schedule 03.10.2019
comment
Это приводит к ошибке: локальный или параметр с именем «основной» не может быть объявлен в этой области, поскольку это имя используется во внешней локальной области для определения локального или параметра   -  person mheptinstall    schedule 03.10.2019
comment
То, что я использовал в прошлом, может быть в ~/Views/Shared/DisplayTemplates/_Principle.cshtml или ~/Views/Principals/_Principle.cshtml, если вы используете его в папке страницы, я не уверен, как был настроен механизм просмотра или путь маршрута, сначала попробуйте его по пути по умолчанию, иначе вы используете его внутри области?   -  person sairfan    schedule 03.10.2019
comment
@sairfan Я получаю одинаковый результат независимо от того, находятся ли они в папке «Страницы» или в папке «Просмотр». Использование проекта веб-приложения ASP.NET Core с .NET Core/Framework не работает. Использование проекта веб-приложения ASP.NET (.NET Framework) работает.   -  person mheptinstall    schedule 03.10.2019
comment
нашел этот ответ здесь посмотреть, если это что-то полезное и это тоже может помочь   -  person sairfan    schedule 03.10.2019


Ответы (1)


Причина

Основной DisplayTemplate используется для всех элементов в списке,

Это потому, что выражение в @Html.DisplayFor(expression) не будет выполняться вообще. Вместо этого они анализируются статически.

Например, если у нас есть выражение m.a.b.c, где a равно null во время выполнения, @Html.DisplayFor(m => m.a.b.c) по-прежнему может знать шаблон для c.

Поскольку вы объявляете Principals как тип List<Principal> , даже если вы делаете Model.Principals удерживанием UserPrincipal или GroupPrincipal во время выполнения, "парсер" по-прежнему рассматривать principal как базовый тип Principal: они не проверяют реальный тип экземпляра. Они просто разбирают тип статически.

Как исправить

Передайте имя шаблона при вызове Html.DisplayFor(), чтобы Html Helper знал реальный шаблон, который вы хотите использовать:

@page
@model IndexModel

@foreach (var principal in Model.Principals)
{
    @Html.DisplayFor(p => principal, principal.GetType().Name)
}

Демо

введите здесь описание изображения

person itminus    schedule 04.10.2019