簡體   English   中英

如何在asp:Repeater中更改ItemTemplate?

[英]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類,以及類等的兒童ContactSearchResultNewsArticleSearchResultsearchResultsRepeater.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”在<% ... %>括號內給出“名稱”“ Container”在當前上下文中不存在”。

嘗試2:將asp:PlaceHolder設置為Visible = False

我發現了一些對更改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:RepeaterItemTemplate絕對不包含任何內容:

    <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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM