導言
在前面的教程裡我們學習了DataList提供了一些風格樣式的屬性.而且我們還學習了如何定義HeadStyle, ItemStyle, AlternatingItemStyle, 和SelectedItemStyle等屬性的預設CSS.除了這四個屬性外,DataList還提供了其它屬性,比如Font, ForeColor, BackColor, 和BorderWidth.而Repeater沒有提供任何這樣的屬性.如果你需要用Reperter來實現這些效果,你就需要在
templates裡直接寫標記語言.
通常,資料需要怎樣的格式取決於資料本身.比如,我們可能使用灰色的字型列出那些被停止使用的product,或者在UnitsInStock等於0的時候顯示高亮.前面的教程裡我們已經學習了GridView, DetailsView, 和FormView 都提供了兩種截然不同的格式化資料的方法.
- DataBound 事件— 為DataBound 事件建立一個合適的event handler, 它在資料繫結到item的時候激發(對GridView來說是RowDataBound 事件; 對 DataList 和Repeater來說是 ItemDataBound 事件). 在這些事件裡, 剛剛繫結資料可以被格式化. 參見基於資料的自訂格式化 這章.
- Templates 的格式化功能— 在DetailsView 或GridView 裡使用TemplateFields , 或 在FormView 裡使用template , 我們可以在ASP.NET page的code-behind class裡或者BLL裡,或者任何其它web程式裡可以調用的類庫裡加格式化資訊. 這種格式化功能可以接收任意的輸入參數, 但是在template裡比如返回HTML . 格式化功能最早在在GridView控制項中使用TemplateField 這章裡談到過.
這兩種方法都可以在DataList和Repeater裡使用.在本章裡我們將一步步用這兩種方法在這兩個控制項裡做樣本.
使用 ItemDataBound Event Handler
當資料繫結到 DataList時, 無論是使用資料來源控制項或者 直接在代碼裡使用DataSource 和 DataBind() , DataList的DataBinding 事件都會被激發. DataList 為資料來源的每條記錄建立一個 DataListItem 對象,然後綁定到目前記錄. 在這個過程中DataList 激發兩個事件:
- ItemCreated — 在建立DataListItem 後激發
- ItemDataBound — 目前記錄綁定到DataListItem 後激發
下面列出了DataList資料繫結過程的大概步驟
- DataList的DataBinding event 被激發
- DataList
對資料來源的每條記錄...
For each record in the data source…
- 建立一個DataListItem 對象
- 激發ItemCreated event
- 綁定記錄到DataListItem
- 激發ItemDataBound event
- 將DataListItem 添加到Items collection
當資料繫結到Repeater時,和上面所說的情況一樣.唯一的區別在於,DataListItem換成了RepeaterItem.
注意:細心的讀者可能注意到了DataList和Repeater綁定到資料時的步驟順序和GridView有些許差別.在資料繫結過程的後期,GridView會激發DataBound事件,而DataList和Repeater則都沒有這個事件.
和GridView一樣,可以為ItemDataBound事件建立一個event handler 來格式化資料.這個event handler 可以處理剛剛綁定到DataListItem或RepeaterItem的資料,來按照需要進行格式化.
對DataList來說,可以使用風格樣式相關的屬性,如Font, ForeColor, BackColor, CssClass等,來格式化item.而如果你想格式化Datalist裡的template裡的web控制項,你需要編程去擷取這些控制項,然後來控制.我們在Custom Formatting Based Upon Data一章裡已經看過怎樣做.和Repeater控制項一樣,RepeaterItem類也沒有風格樣式相關的屬性,因此,你需要在ItemDataBound event handler裡編程去實現.
由於在DataList和Repeater裡使用ItemDataBound格式化技術從本質上來說是由於的,因此我們的樣本主要講DataList.
第一步: 在DataList顯示Product 資訊
Before we worry about the formatting, let’s first create a page that uses a DataList to display product information. In the previous tutorial we created a DataList whose ItemTemplate displayed each product’s name, category, supplier, quantity per unit, and price. Let’s repeat this functionality here in this tutorial. To accomplish this, you can either recreate the DataList and its ObjectDataSource from scratch, or you can copy over those controls from the page created in the previous tutorial (Basics.aspx) and paste them into the page for this tutorial (Formatting.aspx).
在學習格式化之前,我們首先建立一個使用DataList顯示product資訊的頁面.在前面一章裡,我們建立了一個ItemTemplate顯示product 的name,category, supplier, quantity和price的DataList.我們在本章來重複做一次.你可以重新建立DataList和它的ObjectDataSource ,或者直接把前面一章裡的Basics.aspx裡的控制項複製到本章的頁面(Formatting.aspx)裡.
當你完成了Formatting.aspx後,將DataList的ID從DataList1改為ItemDataBoundFormattingExample.
下面,在瀏覽器裡看看DataList.1所示,唯一的格式在於每個product的交替的背景色.
圖 1: 在DataList 裡列出product資訊
在本章教程裡,我們來將價格小於 $20.00 的product的名字和單價用黃色 高亮來顯示.
第二步: 在 ItemDataBound Event Handler裡編程判斷資料的值
由於只有價格低於$20.00 的product會被格式化,因此我們首先要判斷每個product的價格.在綁定資料到DataList時,DataList 為每條資料來源的記錄建立一個DataListItem執行個體,並綁定資料.當記錄綁定到DataListItem對象後,ItemDataBound事件被激發.我們可以為這個事件建立一個event handler來判斷當前DataListItem的值,再根據這個值來格式化資料.
Create an ItemDataBound event for the DataList and add the following code:
添加以下代碼為DataList建立ItemDataBound事件
C# |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
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 event handler在概念和語義上來說,和GridView的RowDataBound event handler一樣(見基於資料的自訂格式化),文法上有一點差別.當ItemDataBound事件激發時,剛剛綁定資料的DataListItem通過e.Item(在GridView裡是e.Row和RowDataBound)傳遞給相關的event handler.DataList的ItemDataBound event handler影響到每一行,包括 header , footer 和separator.但是product資訊只綁定到data行.因此,在處理ItemDataBound事件前,我們首先要判斷處理的是否是data行.這個可以通過檢查DataListItem的ItemType 屬性來完成,它可以有以下八個值:
- AlternatingItem
- EditItem
- Footer
- Header
- Item
- Pager
- SelectedItem
- Separator
Item和AlternatingItem都表示DataList的data item.假設我們在處理Item或AlternatingItem,我們可以擷取綁定到當前DataListItem的ProductsRow的執行個體.DataListItem的DataItem屬性包含了DataRowView對象的引用,通過它的Row屬性可以擷取ProductsRow對象.
下面我們來檢查ProductsRow執行個體的單價屬性.由於Product表的UnitPrice欄位允許空值,所以在擷取UnitPrice屬性前我們應該先用IsUnitPriceNull()方法檢查這個值是否為空白.如果不是,我們再檢查看它是否低於$20.00.如果是,我們就進行格式化處理.
第三步: 是Product的 Name 和Price高亮顯示
一旦我們發現Product的price低於$20.00,我們將使它的name和price顯示高亮.首先我們要編程獲得ItemTemplate裡顯示Product的name和price的Label控制項.然後我們將它的背景色顯示為黃色.這個可以直接通過修改Label空間的BackColor屬性(LabelID.BackColor = Color.Yellow).當然最理想的做法是所有的顯示相關的行為都通過CSS來實現.實際上我們在基於資料的自訂格式化一章裡建立的Styles.css - AffordablePriceEmphasis已經提供了這個功能.
使用以下代碼設定兩個Label控制項的CssClass 屬性為AffordablePriceEmphasis來完成格式化:
C# |
1 2 3 4 5 6 7 8 9 10 11 |
// 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 的product的name和prict都高亮顯示了.
圖2: 價格低於$20.00 的product都被高亮顯示
注意:由於DataList使用 HTML <table>, DataListItem執行個體有可以設定整個item風格的屬性.比如,如果我們想在price低於$20.00時將所有的item都用黃色來高亮顯示,我們可以用e.Item.CssClass = "AffordablePriceEmphasis"來代替上面的代碼(見圖3).
而組成Repeater的RepeaterItem並沒有提供這樣的屬性.因此,在Repeater裡自訂格式需要設定templates裡的控制項的格式,象在圖2裡所做的那樣.
圖 3: The Entire Product Item is Highlighted for Products Under $20.00
使用 Template的格式化功能
在在GridView控制項中使用TemplateField 一章裡,我們學習了如何使用GridView TemplateField的格式化功能來格式化GridView的資料.格式化功能是一種可以從template裡調用並返回HTML顯示的方法.格式化功能可以寫在ASP.NET page的 code-behind class 或App_Code 檔案夾裡的類檔案裡或單獨的類庫項目裡.如果你想在其它ASP.NET web程式或多個ASP.NET 頁用到同樣的功能,那麼不要把它下在ASP.NET page的 code-behind class 裡.
為了示範這個功能,我們將修改product資訊.如果product被停用,我們在product的name後面增加一個“[DISCONTINUED]”的text.同樣的,如果price低於 $20.00 我們將會用黃色來高亮顯示(如我們在ItemDataBound event handler例子裡做的那樣).如果price等於或高於 $20.00,我們將不顯示實際的價格,而是在text裡顯示“Please call for a price quote”. 圖4是完成以上功能的頁面.
圖 4: 將比較貴的Products 的價格用文本“Please call for a price quote”來代替.
第一步: 建立格式化功能
這個例子裡我們需要兩個格式化功能,其一是在被停用的product name後面加上“[DISCONTINUED]”, 其二是對價格低於$20.00的product高亮顯示,其它則顯示“Please call for a price quote”.我們將在ASP.NET page的code-behind class 裡建立這些功能,並給它們取名為DisplayProductNameAndDiscontinuedStatus 和DisplayPrice.這兩個方法都需要返回HTML,而且為了在ASP.NET page的聲明文法裡調用,都需要標記為Protected (or Public).下面是這兩個方法的代碼:
C# |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
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).如果格式化功能處理可能包含資料庫空值(比如UnitPrice,而ProductName和Discontinued都不允許空)的量值,要特別小心處理.
輸入的值可能是一個DBNull而不是你期望的資料類型,因此輸入參數的類型必須為Object.而且比如檢查傳進來的值是否為database NULL.也就是說,如果我們想讓DisplayPrice 方法以價格為參數,我們需要以下代碼:
C# |
1 2 3 4 5 6 7 8 9 10 |
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傳進來的,所以必須要類型轉換為decimal.
第二步: 在DataList 的ItemTemplate調用格式化方法
在完成以上代碼後,剩下的工作就是在DataList的ItemTemplate裡調用這些格式化功能.我們需要使用以下代碼:
ASP.NET |
1 |
<%# MethodName(inputParameter1, inputParameter2, ...) %> |
在DataList的ItemTemplate裡,ProductNameLabel Label通過指定text屬性為<%# Eval("ProductName") %>顯示的product的name.為了在需要的情況下加上“[DISCONTINUED]” ,修改代碼,使用DisplayProductNameAndDiscontinuedStatus 方法來指定text屬性.我們需要使用Eval("columnName") 文法來將product的name和discontinued的值傳進去.Eval 返回的值為Object類型,而DisplayProductNameAndDiscontinuedStatus 的參數為String 和Boolean.因此,我們需要將Eval 方法返回的值轉換為需要的參數類型,代碼如下:
ASP.NET |
1 2 3 4 5 |
<h4> <asp:Label ID="ProductNameLabel" runat="server" Text='<%# DisplayProductNameAndDiscontinuedStatus((string) Eval("ProductName"), (bool) Eval("Discontinued")) %>'> </asp:Label> </h4> |
和顯示product的name和“[DISCONTINUED]” 文本一樣,我們設定UnitPriceLabel label的屬性為DisplayPrice 的傳回值來顯示價格.我們將ProductsRow作為參數,而不是UnitPrice:
ASP.NET |
1 2 3 |
<asp:Label ID="UnitPriceLabel" runat="server" Text='<%# DisplayPrice((Northwind.ProductsRow) ((System.Data.DataRowView) Container.DataItem).Row) %>'> </asp:Label> |
完成以上代碼後,在瀏覽器裡看一下頁面.你的頁面應該和圖5看起來差不多.
圖 5: 將比較貴的Products 的價格用文本“Please call for a price quote”來代替
總結
基於資料格式化DataList或Repeater有兩種方法.一種是為ItemDataBound 建立event handler .ItemDataBound 在資料來源的每條記錄綁定到DataListItem 或RepeaterItem時被激發.在ItemDataBound event handler裡,可以判斷當前item的資料並格式化,而對DataListItem可以格式化整個item.
另一種是通過格式化功能來完成自訂格式化.格式化功能是一種可以從template裡調用並返回HTML顯示的方法.通常,通過判斷綁定到當前item的值來決定返回什麼樣的HTML.這些值或者綁定到item的對象可以傳遞到格式化功能裡.