![](/img/trans.png)
[英]With a custom control that's inside of an ItemTemplate (Repeater), how can I access values from the repeater item?
[英]How do I vary my ItemTemplate inside an asp:Repeater?
我有一個用於顯示搜索結果的用戶控件。 顯示的每個結果的HTML將根據顯示的結果類型而有所不同:以一種方式顯示“聯系人”,以另一種方式顯示“新聞文章”,依此類推。大約有10種不同類型的結果都被標記他們使用HTML時的方式有所不同-因此我需要大約10個左右的模板來顯示單個結果,我可以根據所顯示的當前項目在這些模板之間進行選擇。
我正在使用asp:Repeater
來顯示結果,但是我不知道如何在asp:Repeater <ItemTemplate>
選擇合適的模板。 理想情況下,我希望ASP根據通過searchResultsRepeater.DataSource
傳遞的對象類型來選擇要使用的模板,但不幸的是,我不能使用switch on type( 有關C#switch on type的信息,請參見此博客條目 )。 但是,我只能通過一個用於顯示結果類型的枚舉值。
在后端C#代碼我有一個抽象內聯SearchResult
類,以及類等的兒童ContactSearchResult
, NewsArticleSearchResult
等searchResultsRepeater.DataSource
將被綁定到一個List<SearchResult>
。 每個SearchResult
包含一個ResultListingType type
字段,該字段提供要顯示的列表的類型。
我的第一次嘗試是這樣的:
<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”在當前上下文中不存在”。 我發現了一些對更改asp:repeater中使用的ItemTemplate有用的東西? 。 然后我嘗試了類似的東西:
<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");
}
不幸的是,這不起作用,因為即使在我將Visible = false
設置為ASP后,ASP似乎仍在運行PlaceHolder的內容。 我得到的錯誤“的DataBinding:‘usercontrols_ResultsListing + ContactResultsListing’不包含名為‘newsHeadline’屬性” -即newsResultListing
占位符還在尋找“newsHeadline”字段,即使該字段不為結果存在正在顯示列表類型。
實際上,我已經嘗試過快速測試throw new Exception("e");
在我的ItemDataBound中,甚至在控制流到達ItemDataBound方法之前,都似乎引發了“ DataBinding”錯誤,因此,我在該錯誤中實際上無能為力。
我想我可以將每個字段添加到父類中,而在我的孩子中將大多數字段保留為空,但這看起來確實很丑。
有沒有辦法使這項工作有效,或者有一種更簡便的方法可以根據我當前正在迭代的Container.DataItem的類型來更改ItemTemplate? 我對ASP非常陌生,因此可能缺少一些簡單的東西。 :)
好的,我想我已經找到了一種解決方案—我創建了多個其他用戶控件,每種搜索結果類型一個。 這些控件中的每個控件都為其相應類型的搜索結果定義HTML模板。
我的asp:Repeater
的ItemTemplate
絕對不包含任何內容:
<asp:Repeater ID="searchResultsRepeater" runat="server">
<ItemTemplate>
<%-- empty template: we insert usercontrols in the ItemDataBound --%>
</ItemTemplate>
</asp:Repeater>
我像以前一樣將List<SearchResultData>
綁定到我的asp:Repeater
,並且像以前一樣,此列表根據要顯示的結果類型包含SearchResultData
的更多特定子類型。
在我的ItemDataBound
處理程序中,我根據e.Item.DataItem
的數據類型實例化這些用戶控件之一,然后將該用戶控件插入轉發器:
var aspxItem = e.Item;
var dataItem = (SearchResultData) e.Item.DataItem;
if (dataItem is ContactSearchResult.ContactSearchResultData)
{
var contactSearchResultUC = LoadControl("~/UserControls/ResultsListingSearchResult/ContactSearchResult.ascx") as ASP.ContactSearchResult;
contactSearchResultUC.data = (ContactSearchResult.ContactSearchResultData)dataItem;
aspxItem.Controls.Add(contactSearchResultUC);
}
else if (dataItem is NewsArticleSearchResult.NewsArticleSearchResultData)
{
var newsArticleSearchResultUC = LoadControl("~/UserControls/ResultsListingSearchResult/NewsArticleSearchResult.ascx") as ASP.NewsArticleSearchResult;
newsArticleSearchResultUC.data = (NewsArticleSearchResult.NewsArticleSearchResultData)dataItem;
aspxItem.Controls.Add(newsArticleSearchResultUC);
}
...etc
要添加到George的解決方案中, <ItemTemplate>
可以是標記和動態控件的組合。 下面的示例呈現一個名稱/值對表。
<table cellspacing="0" cellpadding="5" border="0" width="100%">
<tbody>
<asp:Repeater ID="TheRepeater" OnItemDataBound="TheRepeater_ItemDataBound" runat="server">
<ItemTemplate>
<tr>
<td class="LabelText"><%# ((NameValuePair)Container.DataItem).Name%>:</td>
<td class="ValueText">
<asp:PlaceHolder ID="ValuePlaceHolder" runat="server" />
</td>
</tr>
</ItemTemplate>
</asp:Repeater>
</tbody>
</table>
后台代碼
protected void TheRepeater_ItemDataBound(object sender, RepeaterItemEventArgs e)
{
if (ListItemType.Item == e.Item.ItemType || ListItemType.AlternatingItem == e.Item.ItemType)
{
NameValuePair nvp = (NameValuePair)e.Item.DataItem;
PlaceHolder container = (PlaceHolder)e.Item.FindControl("ValuePlaceHolder");
if (typeof(nvp.Value) is String)
{
Literal textControl = new Literal() { Mode = LiteralMode.Encode, Text = (string)nvp.Value, EnableViewState = false };
container.Controls.Add(textControl);
}
...
您將需要重寫ItemDataBound事件處理程序並在那里進行控制。
或者,將邏輯放入用戶控件中,然后將用戶控件放入模板中。
用戶控件仍將需要實施適當的切換,但是可以更輕松地重用邏輯。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.