由 斯科特·米切爾
在本教學課程中,我們將逐步解說如何格式化 DataList 和 Repeater 控件外觀的範例,方法是使用範本內的格式化函式或處理 DataBound 事件。
簡介
如上一個教學課程中所見,DataList 提供一些會影響其外觀的樣式相關屬性。 特別是,我們已瞭解如何將預設 CSS 類別指派給 DataList 的 HeaderStyle、 ItemStyle、 AlternatingItemStyle和 SelectedItemStyle 屬性。 除了這四個屬性之外,DataList 還包含一些其他樣式相關屬性,例如 Font、 ForeColor、 BackColor和 BorderWidth,以命名幾個屬性。 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 控件的數據系結程式。
DataList 的事件
DataBinding觸發。數據系結至 DataList
針對數據源中的每個記錄
- 建立
DataListItem物件 -
ItemCreated觸發事件 - 將記錄綁定至
DataListItem -
ItemDataBound觸發事件 - 將
DataListItem新增至Items集合
- 建立
將數據系結至 Repeater 控制項時,它會逐步執行完全相同的步驟序列。 唯一的差別在於,重複程式不是建立DataListItem的實例,而是使用RepeaterItems。
備註
精明的讀者可能會注意到,當 DataList 和 Repeater 綁定到數據時,與 GridView 綁定到數據時,步驟序列之間存在一些輕微的異常。 在數據系結程序的結尾處,GridView 會 DataBound 引發 事件;不過,DataList 和 Repeater 控件都沒有這類事件。 這是因為 DataList 和 Repeater 控制項是在 ASP.NET 1.x 版本期間建立的,前置和後置事件處理程式模式在之後才逐漸變得常見。
和 GridView 一樣,根據數據格式化的選項之一是為 ItemDataBound 事件建立事件處理常式。 此事件處理程式會檢查剛剛系結至 DataListItem 或 RepeaterItem 的數據,並根據需要調整控件的格式。
針對 DataList 控制,您可以使用樣式相關的屬性來實作整個項目的格式變更,包括標準 DataListItem、Font、ForeColor、BackColor 等。 若要影響 DataList 範本中特定 Web 控件的格式設定,我們需要以程式設計方式存取和修改這些 Web 控件的樣式。 我們看到如何在 以數據為基礎的自定義格式 教學中完成這個方法。 如同 Repeater 控制項,類別RepeaterItem沒有樣式相關屬性;因此,必須在範本內以程式設計方式存取和更新 Web 控制項,來完成對 事件處理程式中 RepeaterItem 所做的所有樣式相關變更ItemDataBound。
ItemDataBound由於 DataList 和 Repeater 的格式技術幾乎完全相同,因此我們的範例將著重於使用 DataList。
步驟 1:在 DataList 中顯示產品資訊
在擔心格式設定之前,讓我們先建立使用 DataList 來顯示產品資訊的頁面。 在上一個 教學課程中 ,我們建立了一個 DataList,其 ItemTemplate 會顯示每個產品名稱、類別、供應商、每個單位的數量和價格。 讓我們在此教學課程中重複這項功能。 若要達成此目的,您可以從頭開始重新建立DataList及其 ObjectDataSource,也可以從上一個教學課程中建立的頁面複製這些控件,並將其貼到本教學課程的頁面Basics.aspx(Formatting.aspx)。
將 DataList 和 ObjectDataSource 功能 Basics.aspx 從 複寫到 Formatting.aspx之後,請花點時間將 DataList 的 ID 屬性從 DataList1 變更為更具描述性的 ItemDataBoundFormattingExample。 接下來,在瀏覽器中檢視 DataList。 如圖 1 所示,每個產品之間的唯一格式差異是背景色彩替代。
圖 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 屬性來完成,其可具有下列八個值之一:
AlternatingItemEditItemFooterHeaderItemPagerSelectedItemSeparator
兩者 Item 和 AlternatingItem``DataListItem 組成 DataList 的資料項。 假設我們正使用 Item 或 AlternatingItem,我們會存取系結至目前 ProductsRow的實際DataListItem實例。
DataListItem 的 DataItem 屬性包含對 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 的產品,其名稱和價格都醒目提示。
圖 2:那些小於 $20.00 的產品已醒目提示 (按兩下以檢視完整大小的影像)
備註
由於 DataList 會轉譯為 HTML <table>,因此其 DataListItem 實例具有樣式相關屬性,可設定為將特定樣式套用至整個專案。 例如,如果我們想要在價格低於 $20.00 時高亮顯示 整個 項目為黃色,我們可以替換引用標籤的程式碼,並使用下列程式碼行設定其 CssClass 屬性:e.Item.CssClass = "AffordablePriceEmphasis"(請參閱圖 3)。
RepeaterItem 不過,組成 Repeater 控件的元件不提供這類樣式層級的屬性。 因此,將自定義格式套用至 Repeater 需要將樣式屬性套用至 Repeater 範本內的 Web 控制件,就像我們在圖 2 中所做的一樣。
圖 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 顯示已套用這些格式規則的產品清單螢幕快照。
圖 4:對於昂貴的產品,價格會取代為文字,請呼叫價位報價(按兩下以檢視全尺寸影像)
步驟 1:建立格式化函式
在此範例中,我們需要兩個格式化函式,一個用於顯示產品名稱及文字 [DISCONTINUED](如有需要),另一個用於顯示突出顯示的價格(如果價格小於 $20.00),否則顯示「請來電詢價」。 讓我們在 ASP.NET 頁面的程式代碼後置類別中建立這些函式,並將其命名為 DisplayProductNameAndDiscontinuedStatus 和 DisplayPrice。 這兩種方法都需要傳回 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 中,ItemTemplate 的 ProductNameLabel 標籤 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 的產品,其價格將替換為文字"請來電詢問價格"。
圖 5:對於昂貴的產品,價格會取代為文字,請呼叫價位報價(按兩下以檢視全尺寸影像)
總結
您可以使用兩種技術,根據數據格式化 DataList 或 Repeater 控件的內容。 第一個技巧是為 ItemDataBound 事件建立事件處理程式,當數據源中的每個記錄繫結至新的 DataListItem 或 RepeaterItem 時,它就會觸發。 在 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給我留言。