DisplayTemplate игнорируется (ковариантный интерфейс?)
Это странно. У меня есть следующий файл просмотра (Views/Search/Submit.cshtml
):
@model IEnumerable<KeyValuePair<string, ISearchProvider>>
@foreach (var provider in Model)
{
var results = provider.Value.Results.Take(10);
if (results.Count() > 0)
{
<text><li class="dropdown-header">@provider.Key</li></text>
@Html.DisplayFor(x => results)
}
}
... где results
это System.Collections.Generic.IEnumerable<out T>
, а также T is ISearchMatch
,
Затем я определил шаблон отображения в Views/Search/DisplayTemplates/SiteSearchMatch.cshtml
;
@model SiteSearchMatch
<li>@Html.ActionLink(Model.Name, "details", "site", new { Id = Model.Id }, null)</li>
... а также SiteSearchMatch
инвентарь ISearchMatch
вот так;
public class SiteSearchMatch: ISearchMatch
{
public int Id { get; set; }
public string Name { get; set; }
}
Я ожидаю, что мой шаблон дисплея будет использоваться; но это не так. Вместо этого вывод, который я вижу, является выводом;
<li class="dropdown-header">sites</li>
11147166811481897189813271028
... где эта строка чисел является комбинацией всех Id
с ISearchMatch
Я хотел сделать с помощью шаблона отображения.
Кажется, Бритва просто делает ISearchMatch
использование первого атрибута, определенного в классе; если я уберу определение Id
собственность, я вместо этого вижу комбинацию всех Name
из ISearchMatch
"S.
Кто-нибудь знает, почему это происходит, и как я могу заставить Razor использовать указанный мной шаблон отображения?
2 ответа
Хромой ответ - "Действие по сборке" в моем файле View Views/Search/DisplayTemplates/SiteSearchMatch.cshtml
было установлено "Нет", а не "Содержимое".
Это означало, что код работал нормально при запуске в режиме отладки в Visual Studio, но не работал при любом развертывании.
Просто чтобы повторить; это исправление не требовало изменений кода. Просто измените "Build Action" обратно на "Content".
Ваше ожидание неверно:
Я ожидаю, что мой шаблон дисплея будет использоваться; но это не так.
Вывод, который вы видите, это просто ID. Я подозреваю, что ваш ISearchMatch
-интерфейс только выставляет Id
-свойства, но это не имеет значения. Важным является фактический тип экземпляра результата. В вашем случае следующая строка:
@Html.DisplayFor(x => results)
может быть неявно оценено как
HtmlHelper<IEnumerable<KeyValuePair<string, ISearchProvider>>>
.DisplayFor<IEnumerable<KeyValuePair<string, ISearchProvider>>, IEnumerable<ISiteMatch>>
(Func<IEnumerable<KeyValuePair<string, ISearchProvider>>, IEnumerable<ISiteMatch>> expression);
Выглядит довольно сложно, но в основном это просто неявная замена вашей модели и результата выражения. Ваша модель имеет тип IEnumerable<KeyValuePair<string, ISearchProvider>>
, Это также тип ввода вашего лампда-выражения. Результат имеет тип IEnumerable<ISiteMatch>
, И здесь самое главное!
DisplayFor
реализация проверяет, является ли тип результата перечислимым или нет. Если нет, он ищет подходящий шаблон для типа, в противном случае он будет перебирать элементы и делает это для всех элементов. 1
Поиск шаблона работает на основе имени типа. В вашем случае шаблон использует имя перечисляемого типа, которое ISearchMatch
, Он не находит шаблон отображения, поэтому просто выводит свойства, в результате чего вы видите:
11147166811481897189813271028
Чтобы решить эту проблему, вам нужно сначала преобразовать набор результатов в правильный тип. Вы можете сделать это по-разному. Либо вы разыгрываете весь результат результатов вашего провайдера:
var results = provider.Value.Results
.Cast<SiteSearchMatch>()
.Take(10);
или вы произносите их индивидуально в своем выражении ламда:
@Html.DisplayFor(x => (SiteSearchMatch)results)
Важно то, что скалярный тип результата совпадает с моделью в вашем шаблоне отображения.
1 Обратите внимание, что это немного сложнее, например, расширение также отслеживает индекс и применяет его к выходным данным, чтобы модель могла быть привязана для целей обратной передачи.