共用方式為


根據資料格式化 DataList 和 Repeater 控制項 (C#)

斯科特·米切爾

下載 PDF

在本教學課程中,我們將逐步解說如何格式化 DataList 和 Repeater 控件外觀的範例,方法是使用範本內的格式化函式或處理 DataBound 事件。

簡介

如上一個教學課程中所見,DataList 提供一些會影響其外觀的樣式相關屬性。 特別是,我們已瞭解如何將預設 CSS 類別指派給 DataList 的 HeaderStyleItemStyleAlternatingItemStyleSelectedItemStyle 屬性。 除了這四個屬性之外,DataList 還包含一些其他樣式相關屬性,例如 FontForeColorBackColorBorderWidth,以命名幾個屬性。 Repeater 控制件不包含任何樣式相關的屬性。 任何這類樣式設定都必須直接在 Repeater 範本的標記內進行。

不過,數據格式通常取決於數據本身。 例如,當列出產品時,如果某產品已停產,我們可能會想要以淺灰色字體顯示其資訊;或者如果UnitsInStock的值為零,我們可能會想要以突出方式顯示該值。 如上一個教學課程中所見,GridView、DetailsView 和 FormView 提供兩種不同的方式,可根據數據格式化其外觀:

  • 事件DataBound會為適當的事件創建事件處理程式,該事件處理程式會在數據綁定至每個項目之後引發(對於 GridView,則是DataBound事件;對於 DataList 和 Repeater,則是RowDataBound事件)。 在該事件處理程式中,可以檢查剛系結的數據,並作出格式化的決策。 我們在 根據數據的自訂格式 教學課程中研究了這項技術。
  • 在模板中的格式化功能 當在 DetailsView 或 GridView 控制項中使用 TemplateFields,或在 FormView 控制項中使用模板時,我們可以將格式化函數新增至 ASP.NET 頁面的程式碼後置類別、商務邏輯層,或可從 Web 應用程式存取的任何其他類別庫。 此格式設定函式可以接受任意數目的輸入參數,但必須傳回 HTML 才能在範本中呈現。 在使用 GridView 控制項中的 TemplateFields 教學課程中,首先探討了格式化函式。

這兩種格式技術都可透過 DataList 和 Repeater 控件取得。 在本教程中,我們將逐步展示如何對兩個控件使用兩種技術的範例。

ItemDataBound使用事件處理程式

當數據系結至 DataList 時,無論是從數據源控件,還是透過以程式設計方式將數據指派給控件的 DataSource 屬性,並呼叫其 DataBind() 方法時,DataList 事件 DataBinding 就會引發、列舉數據源,而且每個數據記錄都會系結至 DataList。 針對數據源中的每個記錄,DataList 會 DataListItem 建立對象,然後系結至目前的記錄。 在此程式中,DataList 會引發兩個事件:

  • ItemCreated 建立後,DataListItem 被觸發
  • ItemDataBound 在目前記錄已綁定到 DataListItem 後觸發

下列步驟概述 DataList 控件的數據系結程式。

  1. DataList 的事件DataBinding觸發。

  2. 數據系結至 DataList

    針對數據源中的每個記錄

    1. 建立 DataListItem 物件
    2. ItemCreated觸發事件
    3. 將記錄綁定至 DataListItem
    4. ItemDataBound觸發事件
    5. DataListItem新增至Items集合

將數據系結至 Repeater 控制項時,它會逐步執行完全相同的步驟序列。 唯一的差別在於,重複程式不是建立DataListItem的實例,而是使用RepeaterItems。

備註

精明的讀者可能會注意到,當 DataList 和 Repeater 綁定到數據時,與 GridView 綁定到數據時,步驟序列之間存在一些輕微的異常。 在數據系結程序的結尾處,GridView 會 DataBound 引發 事件;不過,DataList 和 Repeater 控件都沒有這類事件。 這是因為 DataList 和 Repeater 控制項是在 ASP.NET 1.x 版本期間建立的,前置和後置事件處理程式模式在之後才逐漸變得常見。

和 GridView 一樣,根據數據格式化的選項之一是為 ItemDataBound 事件建立事件處理常式。 此事件處理程式會檢查剛剛系結至 DataListItemRepeaterItem 的數據,並根據需要調整控件的格式。

針對 DataList 控制,您可以使用樣式相關的屬性來實作整個項目的格式變更,包括標準 DataListItemFontForeColorBackColor 等。 若要影響 DataList 範本中特定 Web 控件的格式設定,我們需要以程式設計方式存取和修改這些 Web 控件的樣式。 我們看到如何在 以數據為基礎的自定義格式 教學中完成這個方法。 如同 Repeater 控制項,類別RepeaterItem沒有樣式相關屬性;因此,必須在範本內以程式設計方式存取和更新 Web 控制項,來完成對 事件處理程式中 RepeaterItem 所做的所有樣式相關變更ItemDataBound

ItemDataBound由於 DataList 和 Repeater 的格式技術幾乎完全相同,因此我們的範例將著重於使用 DataList。

步驟 1:在 DataList 中顯示產品資訊

在擔心格式設定之前,讓我們先建立使用 DataList 來顯示產品資訊的頁面。 在上一個 教學課程中 ,我們建立了一個 DataList,其 ItemTemplate 會顯示每個產品名稱、類別、供應商、每個單位的數量和價格。 讓我們在此教學課程中重複這項功能。 若要達成此目的,您可以從頭開始重新建立DataList及其 ObjectDataSource,也可以從上一個教學課程中建立的頁面複製這些控件,並將其貼到本教學課程的頁面Basics.aspxFormatting.aspx)。

將 DataList 和 ObjectDataSource 功能 Basics.aspx 從 複寫到 Formatting.aspx之後,請花點時間將 DataList 的 ID 屬性從 DataList1 變更為更具描述性的 ItemDataBoundFormattingExample。 接下來,在瀏覽器中檢視 DataList。 如圖 1 所示,每個產品之間的唯一格式差異是背景色彩替代。

產品列在 DataList 控件中

圖 1:產品列在 DataList 控制件中(按兩下以檢視完整大小的影像

在本教學課程中,讓我們設定 DataList 的格式,讓任何價格小於 $20.00 的產品都會以黃色反白顯示其名稱和單價。

步驟 2:以程式設計方式判斷 ItemDataBound 事件處理程式中的數據值

由於只有價格低於 $20.00 的產品才會套用自定義格式,因此我們必須能夠判斷每個產品的價格。 將數據系結至 DataList 時,DataList 會列舉其數據源中的記錄,並針對每個記錄建立 DataListItem 實例,將數據源記錄系結至 DataListItem。 在特定記錄的數據綁定至目前 DataListItem 物件之後,會觸發 DataList 的 ItemDataBound 事件。 我們可以為此事件建立事件處理程式,以檢查目前 DataListItem 的數據值,並根據這些值,進行任何必要的格式變更。

建立 ItemDataBound DataList 的事件,並新增下列程式代碼:

protected void ItemDataBoundFormattingExample_ItemDataBound
    (object sender, DataListItemEventArgs e)
{
    if (e.Item.ItemType == ListItemType.Item ||
        e.Item.ItemType == ListItemType.AlternatingItem)
    {
        // Programmatically reference the ProductsRow instance bound
        // to this DataListItem
        Northwind.ProductsRow product =
            (Northwind.ProductsRow)((System.Data.DataRowView)e.Item.DataItem).Row;
        // See if the UnitPrice is not NULL and less than $20.00
        if (!product.IsUnitPriceNull() && product.UnitPrice < 20)
        {
            // TODO: Highlight the product's name and price
        }
    }
}

雖然 DataList 的 ItemDataBound 事件處理程式背後的概念和語意與 RowDataBound 教學課程中使用的 GridView 的 事件處理程式相同,但語法稍有不同。 ItemDataBound事件觸發時, DataListItem剛剛綁定到的數據會通過e.Item(而不是像 GridView 的e.Row事件處理程式那樣通過RowDataBound)傳遞到對應的事件處理程式。 DataList 的 ItemDataBound 事件處理程式會針對新增至 DataList 的每個 數據列引發,包括頁首數據列、頁尾數據列和分隔符數據列。 不過,產品資訊只會系結至數據列。 因此,當使用 ItemDataBound 事件來檢查系結至 DataList 的數據時,我們必須先確定我們使用數據項。 這可以藉由檢查 DataListItemsItemType 屬性來完成,其可具有下列八個值之一:

  • AlternatingItem
  • EditItem
  • Footer
  • Header
  • Item
  • Pager
  • SelectedItem
  • Separator

兩者 ItemAlternatingItem``DataListItem 組成 DataList 的資料項。 假設我們正使用 ItemAlternatingItem,我們會存取系結至目前 ProductsRow的實際DataListItem實例。 DataListItemDataItem 屬性包含對 DataRowView 對象的參考,其 Row 屬性提供對實際 ProductsRow 對象的參考。

接下來,我們會檢查 ProductsRow 實例的 UnitPrice 屬性。 由於 Products 資料表的 UnitPrice 字段允許 NULL 值,在嘗試存取 UnitPrice 屬性之前,我們應該先檢查它 NULL 是否有使用 IsUnitPriceNull() 方法的值。 UnitPrice如果值不是 NULL,我們會檢查它是否小於 $20.00。 如果它確實低於 $20.00,則我們需要套用自訂格式。

步驟 3:醒目提示產品名稱和價格

一旦我們知道產品的價格小於 $20.00,剩下的就是強調其名稱和價格。 若要達成此目的,我們必須先以程式設計方式參考 顯示產品名稱和價格的標籤 ItemTemplate 控制件。 接下來,我們需要讓他們顯示黃色背景。 您可以直接修改 Label BackColor 屬性來套用此格式資訊。LabelID.BackColor = Color.Yellow在理想情況下,所有顯示相關的事項都應該透過串聯樣式表單來表示。 事實上,我們已經有一個樣式表,提供在 Styles.css - AffordablePriceEmphasis 中定義的所需格式設定,該格式設定是在 基於數據的自定義格式化 教學中建立和討論的。

若要套用格式設定,只要將兩個標籤 Web 控件 CssClass 屬性設定為 AffordablePriceEmphasis,如下列程式代碼所示:

// Highlight the product name and unit price Labels
// First, get a reference to the two Label Web controls
Label ProductNameLabel = (Label)e.Item.FindControl("ProductNameLabel");
Label UnitPriceLabel = (Label)e.Item.FindControl("UnitPriceLabel");
// Next, set their CssClass properties
if (ProductNameLabel != null)
    ProductNameLabel.CssClass = "AffordablePriceEmphasis";
if (UnitPriceLabel != null)
    UnitPriceLabel.CssClass = "AffordablePriceEmphasis";

在完成ItemDataBound事件處理程序之後,請重新在瀏覽器中查看Formatting.aspx頁面。 如圖 2 所示,價格低於 $20.00 的產品,其名稱和價格都醒目提示。

那些小於 $20.00 的產品會醒目提示

圖 2:那些小於 $20.00 的產品已醒目提示 (按兩下以檢視完整大小的影像

備註

由於 DataList 會轉譯為 HTML <table>,因此其 DataListItem 實例具有樣式相關屬性,可設定為將特定樣式套用至整個專案。 例如,如果我們想要在價格低於 $20.00 時高亮顯示 整個 項目為黃色,我們可以替換引用標籤的程式碼,並使用下列程式碼行設定其 CssClass 屬性:e.Item.CssClass = "AffordablePriceEmphasis"(請參閱圖 3)。

RepeaterItem 不過,組成 Repeater 控件的元件不提供這類樣式層級的屬性。 因此,將自定義格式套用至 Repeater 需要將樣式屬性套用至 Repeater 範本內的 Web 控制件,就像我們在圖 2 中所做的一樣。

所有相關產品項目在 $20.00 以下都會被突出顯示

圖 3:針對 $20.00 以下的產品,已醒目提示整個商品(點擊以檢視完整大小的影像

從範本內使用格式化函式

GridView 控件中使用 TemplateFields 教學課程中,我們已瞭解如何在 GridView TemplateField 中使用格式化函式,根據系結至 GridView 數據列的數據套用自定義格式。 格式化函式是從範本叫用的方法,並傳回要在其位置發出的 HTML。 格式化函式可以位於 ASP.NET 頁的程式代碼後置類別中,也可以集中化為資料夾中的類別檔案 App_Code ,或位於個別的類別庫專案中。 如果您打算在多個 ASP.NET 頁面或其他 ASP.NET Web 應用程式中使用相同的格式化函式,將格式化函式移出 ASP.NET 頁面的程式代碼後置類別,就很理想。

為了示範格式化函式,若產品已停止販售,我們會在產品名稱旁加入字樣 [DISCONTINUED]。 此外,如果價格小於 $20.00,讓我們將價格反白顯示為黃色(如我們在事件處理程式範例中 ItemDataBound 所做的一樣):如果價格是 $20.00 或更高,則讓我們不要顯示實際價格,而是文字,請呼叫價位報價。 圖 4 顯示已套用這些格式規則的產品清單螢幕快照。

此螢幕快照顯示 DataList 控件中所列的產品,其中的產品價格超過 $20.00,取代為文字,「請撥打報價」。

圖 4:對於昂貴的產品,價格會取代為文字,請呼叫價位報價(按兩下以檢視全尺寸影像

步驟 1:建立格式化函式

在此範例中,我們需要兩個格式化函式,一個用於顯示產品名稱及文字 [DISCONTINUED](如有需要),另一個用於顯示突出顯示的價格(如果價格小於 $20.00),否則顯示「請來電詢價」。 讓我們在 ASP.NET 頁面的程式代碼後置類別中建立這些函式,並將其命名為 DisplayProductNameAndDiscontinuedStatusDisplayPrice。 這兩種方法都需要傳回 HTML 以轉譯為字串,而且兩者都必須標示 Protected 為 (或 Public),才能從 ASP.NET 頁面的宣告式語法部分叫用。 這兩種方法的程序代碼如下:

protected string DisplayProductNameAndDiscontinuedStatus
    (string productName, bool discontinued)
{
    // Return just the productName if discontinued is false
    if (!discontinued)
        return productName;
    else
        // otherwise, return the productName appended with the text "[DISCONTINUED]"
        return string.Concat(productName, " [DISCONTINUED]");
}
protected string DisplayPrice(Northwind.ProductsRow product)
{
    // If price is less than $20.00, return the price, highlighted
    if (!product.IsUnitPriceNull() && product.UnitPrice < 20)
        return string.Concat("<span class=\"AffordablePriceEmphasis\">",
                              product.UnitPrice.ToString("C"), "</span>");
    else
        // Otherwise return the text, "Please call for a price quote"
        return "<span>Please call for a price quote</span>";
}

請注意,DisplayProductNameAndDiscontinuedStatus方法接受 和 productName 數據欄位的值discontinued做為純量值,而 DisplayPrice 方法則接受 ProductsRow 實例(而非unitPrice純量值)。 任一種方法都能夠運作;不過,如果格式化函式正使用可包含資料庫NULL值的純量值(例如UnitPrice,既不是ProductName也不是Discontinued,亦不允許NULL值),則必須特別小心處理這些純量輸入。

特別是,輸入參數必須是 型 Object 別,因為傳入值可能是 DBNull 實例,而不是預期的數據類型。 此外,必須進行檢查,以判斷傳入值是否為資料庫 NULL 值。 也就是說,如果我們想要 DisplayPrice 方法接受價格做為純量值,我們必須使用下列程序代碼:

protected string DisplayPrice(object unitPrice)
{
    // If price is less than $20.00, return the price, highlighted
    if (!Convert.IsDBNull(unitPrice) && ((decimal) unitPrice) < 20)
        return string.Concat("<span class=\"AffordablePriceEmphasis\">",
                              ((decimal) unitPrice).ToString("C"), "</span>");
    else
        // Otherwise return the text, "Please call for a price quote"
        return "<span>Please call for a price quote</span>";
}

請注意,unitPrice 輸入參數的類型為 Object ,並且條件語句已被修改,以確定 unitPrice 是否為 DBNull。 此外,由於unitPrice輸入參數是以Object傳入的,必須將其轉換成十進位值。

步驟 2:從 DataList s ItemTemplate 呼叫格式化函式

在將格式化功能新增至我們的 ASP.NET 頁面後置程式碼類別後,剩下的就是從 DataList 中調用這些格式化功能 ItemTemplate。 若要從範本呼叫格式化函式,請將函式呼叫放在數據系結語法中:

<%# MethodName(inputParameter1, inputParameter2, ...) %>

在 DataList 中,ItemTemplateProductNameLabel 標籤 Web 控制項目前會通過將其 Text 屬性設定為<%# Eval("ProductName") %>的結果來顯示產品的名稱。 若要讓它顯示名稱加上文字 [DISCONTINUED],如有需要,請更新宣告式語法,將 Text 屬性指派給 DisplayProductNameAndDiscontinuedStatus 方法的值。 這樣做時,我們必須使用 Eval("columnName") 語法傳入產品名稱和已中止的值。 Eval 傳回 Object類型的值,但 DisplayProductNameAndDiscontinuedStatus方法預期 String型別和 Boolean型別的輸入參數,因此,我們必須將 Eval方法傳回的值轉換成預期的輸入參數類型,如下所示:

<h4>
    <asp:Label ID="ProductNameLabel" runat="server"
        Text='<%# DisplayProductNameAndDiscontinuedStatus((string) Eval("ProductName"),
              (bool) Eval("Discontinued")) %>'>
    </asp:Label>
</h4>

為了顯示價格,我們可以簡單地將 UnitPriceLabel Label 的Text屬性設定為由 DisplayPrice 方法所傳回的值,就像我們顯示產品名稱和 [DISCONTINUED] 文字時所做的一樣。 不過,我們改為傳入整個UnitPrice實例,而不是以ProductsRow純量輸入參數的形式傳入 :

<asp:Label ID="UnitPriceLabel" runat="server"
    Text='<%# DisplayPrice((Northwind.ProductsRow)
          ((System.Data.DataRowView) Container.DataItem).Row) %>'>
</asp:Label>

在呼叫格式化函式時,請花點時間在瀏覽器中檢視我們的進度。 您的畫面應該看起來與圖 5 類似,已中止的產品會包含文字 [DISCONTINUED],而價格超過 $20.00 的產品,其價格將替換為文字"請來電詢問價格"。

顯示列出在 DataList 控制項中的產品的螢幕截圖,其中價格超過 $20.00 的產品所示文字為 '請來電詢價',已停止產品名稱則附加文字 '[DISCONTINUED]'。

圖 5:對於昂貴的產品,價格會取代為文字,請呼叫價位報價(按兩下以檢視全尺寸影像

總結

您可以使用兩種技術,根據數據格式化 DataList 或 Repeater 控件的內容。 第一個技巧是為 ItemDataBound 事件建立事件處理程式,當數據源中的每個記錄繫結至新的 DataListItemRepeaterItem 時,它就會觸發。 在 ItemDataBound 事件處理程式中,可以檢查目前項目的數據,然後將格式設定套用至範本的內容,或針對 DataListItem 的項目本身套用格式。

或者,可以透過格式化函式實現自定義格式設定。 格式化函式是一種可以從 DataList 或 Repeater 模板叫用的的方法,返回要在該位置發出的 HTML。 格式化函式所傳回的 HTML 通常是由綁定到當前項目的值來決定。 這些值可以傳遞至格式化函式,可以是純量值,或是傳入系結至專案的整個物件(例如 ProductsRow 實例)。

快樂的程序設計!

關於作者

斯科特·米切爾,七本 ASP/ASP.NET 書籍和 4GuysFromRolla.com 創始人的作者,自1998年以來一直與Microsoft Web 技術合作。 斯科特擔任獨立顧問、教練和作家。 他的最新書是 Sams Teach Yourself ASP.NET 2.0 in 24 Hours。 可以透過 mitchell@4GuysFromRolla.com 聯絡他。

特別感謝

本教學系列已由許多熱心的評論者審閱。 本教學課程的主要檢閱者是 Yaakov Ellis、Randy Schmidt 和 Liz Shulok。 有興趣檢閱我即將推出的 MSDN 文章嗎? 如果是,請在 mitchell@4GuysFromRolla.com給我留言。