У меня есть пользовательский элемент управления, который используется для отображения результатов поиска. HTML для каждого отображаемого результата будет меняться в зависимости от типа отображаемого результата: "контакты" отображаются в одном виде, "новостные статьи" отображаются в другом и т.д. Существует около 10 различных типов результатов, все отмеченные по-разному, когда они попадают в HTML — поэтому мне нужно около 10 или около того разных шаблонов для отдельных результатов, которые я могу выбирать между ними в зависимости от текущего отображаемого элемента.
Я использую asp:Repeater
для отображения результатов, но я не знаю, как выбрать соответствующий шаблон в asp:Repeater <ItemTemplate>
. В идеале я бы хотел, чтобы ASP выбирал подходящий шаблон для использования на основе типа объекта, передаваемого через searchResultsRepeater.DataSource
— но, к сожалению, я не могу использовать тип включения (см. эту запись в блоге для С# switch on type). Однако я могу просто передать значение перечисления для отображаемого типа результата.
В базовом коде С# у меня есть абстрактный встроенный класс SearchResult
и дети этого класса, такие как ContactSearchResult
, NewsArticleSearchResult
и т.д. searchResultsRepeater.DataSource
будет привязан к List<SearchResult>
. Каждый SearchResult
содержит поле ResultListingType type
, которое отображает тип списка.
Попытка 1: использование потока управления внутри самого ASP
Моя первая попытка была примерно такой:
<asp:Repeater ID="searchResultsRepeater" runat="server">
<ItemTemplate>
<div class="item">
<% switch (DataBinder.Eval(Container.DataItem, "type")) { %>
<% case ResultListingType.CONTACT: %>
<p><%# DataBinder.Eval(Container.DataItem, "firstName") %></p>
<p><%# DataBinder.Eval(Container.DataItem, "lastName") %></p>
<% break; %>
<% case ResultListingType.NEWS: %>
<p><%# DataBinder.Eval(Container.DataItem, "newsHeadline") %></p>
<p><%# DataBinder.Eval(Container.DataItem, "newsDate") %></p>
<% break; %>
<% Case AnotherTypeOfListing1: %>
<% Case AnotherTypeOfListing2: %>
<% Case AnotherTypeOfListing3: %>
<% Case AnotherTypeOfListing4: %>
<% Case AnotherTypeOfListing5: %>
<% etc... %>
<% } %>
</div>
</ItemTemplate>
</asp:Repeater>
К сожалению, это не работает:
- "switch" и "if" оба дают "недопустимый термин выражения" внутри скобок
<%# ... %>
. - "Container.DataItem" дает "имя" Контейнер "не существует в текущем контексте" внутри
<% ... %>
скобок.
Попытка 2: установка asp: PlaceHolder to Visible = False
Я нашел что-то полезное в как изменить ItemTemplate, используемый в asp: repeater?. Затем я попробовал что-то вроде:
<asp:Repeater ID="searchResultsRepeater" runat="server">
<ItemTemplate>
<div class="item">
<asp:PlaceHolder ID="newsResultListing" runat="server">
<p><%# DataBinder.Eval(Container.DataItem, "newsHeadline") %></p>
<p><%# DataBinder.Eval(Container.DataItem, "newsDate") %></p>
</asp:PlaceHolder>
<asp:PlaceHolder ID="contactResultListing" runat="server">
<p><%# DataBinder.Eval(Container.DataItem, "firstName") %></p>
<p><%# DataBinder.Eval(Container.DataItem, "lastName") %></p>
</asp:PlaceHolder>
</div>
</ItemTemplate>
</asp:Repeater>
В моем событии ItemDataBound я сделал:
Control newsResultListing = e.Item.FindControl("newsResultListing");
newsResultListing.Visible = false;
Control contactResultListing = e.Item.FindControl("contactResultListing");
contactResultListing.Visible = false;
switch (item.type)
{
case ResultListingType.CONTACT:
contactResultListing.Visible = true;
break;
case ResultListingType.NEWS:
newsResultListing.Visible = true;
break;
default:
throw new Exception("Unknown result listing type");
}
К сожалению, это не работает, потому что ASP, похоже, все еще работает с содержимым PlaceHolder даже после того, как я установил Visible = false
. Я получаю сообщение об ошибке "DataBinding: usercontrols_ResultsListing + ContactResultsListing" не содержит свойства с именем "newsHeadline" "— то есть newsResultListing
PlaceHolder все еще ищет поле "newsHeadline", даже если это поле не существует для отображаемого типа списка результатов.
На самом деле я пробовал быстрый тест throw new Exception("e");
в моем ItemDataBound, и похоже, что ошибка "DataBinding" возникает даже до того, как поток управления переходит к методу ItemDataBound, поэтому я действительно ничего не могу сделать там избегайте этой ошибки.
Я полагаю, я мог бы добавить каждое отдельное поле в родительский класс и оставить большинство из них пустым в моих дочерних элементах, но это кажется действительно уродливым.
Есть ли способ сделать эту работу или более простой способ изменить мой ItemTemplate в зависимости от типа Container.DataItem. Я сейчас выполняю итерацию? Я очень новичок в ASP, поэтому есть что-то простое, что я пропустил.:)