我們可以 通過控制 HeaderStyle , RowStyle , AlternatingRowStyle 和其他一些屬性來 改變 GridView, DetailsView, 和 FormView 的樣式 , 比如 cssClass, Font, BorderWidth , BorderStyle , BorderColor , Width , Height 等
?
一般 , 自定義格式化與我們所要顯示的數據的值有關系。例如 , 為了吸引用戶注意那些庫存為空的產品,我們可以將庫存對應的字段 UnitsInStock ? 和 UnitsOnOrder 為 0 的數據背景色設為黃色 . 為了高亮化那些貴的產品,則將 UnitsInStock ? 高于 $75.00 的數據字體設置為粗體
?
?GridView, DetailsView, FormView 的格式自定義可以有多種方法 , 在本文中我們將用 DataBound 和 RowDataBound 兩種事件來完成, 在下一篇里我們將嘗試用 alternative 的方式 在 GridView 控件中使用 TemplateField ?
?
使用 DetailsView 控件的 DataBound 事件
當綁定數據到 DetailsView 控件 , 不管是從數據控件或編碼填充數據到 DataSource 屬性并調用其 DataBind() 方法。以下幾種事件將觸發
?
- DataBinding 事件觸發
- 數據綁定到數據綁定控件
- DataBound 事件觸發
?
一般在 1,2,3 之后數據將會通過事件立即填充數據控件,我們還可以自定義事件處理來確定數據是否已經被填充到控件中并按照我們的需要調整顯示格式。我們可以來做個例子 . 我們將創建一個 DetailsView 來列出一個產品的一般信息,并且當 UnitPrice 超過 $75.00 時用粗體, italic 字體來顯示 UnitPrice 的值
?
Step 1: 在 DetailsView 中顯示產品信息
在 CustomFormatting 文件夾下 新建一個 CustomColors.aspx 頁面 , 從工具箱中拖出一個 DetailsView 控件到頁面中 , 設置 ID 為 ExpensiveProductsPriceInBoldItalic
綁定到一個新的數據源中,并配置此數據源到業務對象 ProductsBLL 類中的 GetProducts () 方法 , 這個的詳細實現步驟已經在前面詳細介紹過了,這里就忽略了
?
當您綁定
ObjectDataSource
到
DetailsView
時
,
我們可以修改一下字段列表,我選擇移除了
ProductID
,
SupplierID
,
CategoryID
,
UnitsInStock
,
UnitsOnOrder
,
ReorderLevel
和那些不被綁定的字段,他們將不會顯示在
DetailsView
列表中
,
而那些留下來的我們可以重命名他們
,
還可以修改他們的顯示格式
.
我還清空了
DetailsView
的
Height
和
Width
屬性
,
這樣當顯示的只有一條數據時不會出現樣式的混亂。當然我們面對的數據絕不只有一條這么少,顯示怎么辦呢?我們可以檢查
DetailsView
的智能感知中檢查
Enable Paging checkbox
是否被勾選上
,
這樣我們可以分頁查看所有的數據了
圖一 : 在 DetailsView 的值能感知中檢查 Enable Paging 屬性是否被勾選上
?
在經過這些改變后, DetailsView 的代碼更改為
?
< asp : DetailsView ID ="DetailsView1" runat ="server" AllowPaging ="True" AutoGenerateRows ="False" DataKeyNames ="ProductID" DataSourceID ="ObjectDataSource1" EnableViewState ="False"> ??? < Fields > ??????? < asp : BoundField DataField ="ProductName" HeaderText ="Product" SortExpression ="ProductName" /> ??????? < asp : BoundField DataField ="CategoryName" HeaderText ="Category" ReadOnly ="True" SortExpression ="CategoryName" /> ??????? < asp : BoundField DataField ="SupplierName" HeaderText ="Supplier" ReadOnly ="True" SortExpression ="SupplierName" /> ??? ???? < asp : BoundField DataField ="QuantityPerUnit" HeaderText ="Qty/Unit" SortExpression ="QuantityPerUnit" /> ??????? < asp : BoundField DataField ="UnitPrice" DataFormatString ="{0:c}" HeaderText ="Price" ??????????? HtmlEncode ="False" SortExpression ="UnitPrice" /> ??? </ Fields > </ asp : DetailsView > |
?
您這時可以按 F5 執行看看
? 圖二 : DetailsView 控件一次顯示一個數據
Step 2: 在 DataBound 事件中 編碼確定數據的值
為了將那些 UnitPrice 高于 $75.00 的產品用粗體, italic 字體顯示出來 , 我們首先需要編碼確定 UnitPrice 的值 , 對于 DetailsView 我們可以通過 DataBound 事件完成 . 我們選擇 DetailsView 并查看屬性視圖 (F4 位快捷鍵 ), 如果沒有顯示,則選擇 View (視圖)
Property Window( 屬性窗口 ), 在確保您選擇了 DetailsView 的情況下雙擊 DataBound 事件或者輸入您要創建的事件名
?

圖三 : 為 DataBound 事件創建一個事件處理
?
代碼中將會自動生成以下代碼
??? protected void ExpensiveProductsPriceInBoldItalic_DataBound(object sender, EventArgs e) ??? { ? ??? } |
我們可以通過 DataItem 屬性來設置 DetailsView 的綁定項 ( 一些強類型的數據行 (DataRow) 組成的強類型的數據表 (DataTable)), 當數據表 (DataTable) 綁定到 DetailsView 時,數據表的第一行將被自動綁定到 DetailsView 的 DataItem 屬性 , 而 DataItem 屬性中包含有 DataRowView ( Object 類型) , 我們可以通過 DataRowView 來訪問一個 ProductsRow 的 DataRow 實例 , 還可以檢測 Object 的值來確定 ProductsRow 實例是否存在
?
下面的代碼描述如何確定 UnitPrice 是否綁定到 DetailsView 并且高于 $75.00
protected void ExpensiveProductsPriceInBoldItalic_DataBound(object sender, EventArgs e) { ??? // Get the ProductsRow object from the DataItem property... ??? Northwind.ProductsRow product = (Northwind.ProductsRow)((System.Data.DataRowView) ExpensiveProductsPriceInBoldItalic.DataItem).Row;
???
if (!product.IsUnitPriceNull() && product.UnitPrice > ??? { ??????? // TODO: Make the UnitPrice text bold and italic ??? } } |
?
注意 : 當 UnitPrice 在數據庫的值為空,我們在綁定到 ProductsRow ’s UnitPrice 屬性之前檢查確定他是否為空,這很重要因為我們可以通過檢查這個屬性來拋出一個強類型的異常 StrongTypingException exception .
?
Step 3: 在 DetailsView 中格式化 UnitPrice
到這個時候我們已經知道即將綁定的 UnitPrice 是否高于 $75.00, 現在我們來看看怎么通過編碼調整 UnitPrice 的格式 , 我們可以通過修改 DetailsViewID .Rows[index] ; 修改一行數據,而且我們可以通過訪問 DetailsViewID .Rows[index].Cells[index] 來訪問某一單元格 , 這樣我們可以通過修改與格式相關的屬性來格式化這一單元格
?
訪問某一行需要得到某行的索引, 索引從 0 開始 , UnitPrice 在 DetailsView 中是第 15 行 , 假設他在第四行那么我們可以通過 ExpensiveProductsPriceInBoldItalic.Rows[4] 來訪問 . 這時我們可以通過下面的代碼將這一行顯示為粗體, italic 字體
?
ExpensiveProductsPriceInBoldItalic.Rows[4].Font.Bold = true ; ExpensiveProductsPriceInBoldItalic.Rows[4].Font.Italic = true ; |
?
然而,這樣將會格式化 Label 和值,如果我們只想將值格式話,而且我們需要將格式應用到當前行的第二格,請看下面的代碼
?
ExpensiveProductsPriceInBoldItalic.Rows[4].Cells[1].Font.Bold = true; ExpensiveProductsPriceInBoldItalic.Rows[4].Cells[1].Font.Italic = true ; |
?
我們還可以通過 StyleSheet 來顯示標記和樣式相關信息,而不是用確定的某一行某一列來設置格式,我們用 CSS 來控制格式 , 打開 Styles.css 文件,添加一個新的 Class 命名為 ExpensivePriceEmphasis 按照下面的代碼
CSS .ExpensivePriceEmphasis { ??? font-weight: bold; ??? font-style: italic; } |
?
然后再 DataBound 事件中,設置單元的 CssClass 為 ExpensivePriceEmphasis ,在 DataBound 事件處理中添加
?
當查看 Chai( 費用低于 $75.00), 價格將會用正常格式顯示 圖 4) ,但是當查看 Mishi Kobe Niku,( 價格為 $97.00) 則會用我們設置的格式顯示 ( 圖 5)
圖 4: 價格低于 $75.00 將會用正常格式顯示
圖 5: 價格高于 $75.00 將會用 粗體 , Italic 字體顯示
使用 FormView 控件的 DataBound 事件
綁定到 FormView 數據的步驟和 DetailsView 的步驟類似都要創建一個 DataBound 事件處理 , 聲明綁定到控件的 DataItem 類型屬性 , 然后執行綁定。然而,他們更新的方式不同
?
FormView 不包括任何綁定列也不包含行的集合 , 取而代之的是他由一系列包含若干靜態 HTML , Web 控件,綁定表達式的模板組合。調整 FormView 的外觀涉及到調整一個或多個 FormView 的模板
?
讓我們像前一個例子那樣用 FormView 列出產品項,但是這次我們僅僅用紅色字體顯示 units 小于等于 10 的產品的 name 和 units
?
Step 1: 在 FormView 中顯示產品信息
添加一個 FormView 到 CustomColors.aspx 中,設置其 ID 為 LowStockedProductsInRed , 像前一個步驟一樣綁定數據到 ObjectDataSource 中, 這將在 FormView 中創建 ItemTemplate , EditItemTemplate , 和 InsertItemTemplate ?. 移除 EditItemTemplate 和 InsertItemTemplate 并在 ItemTemplate 中僅包含 ProductName 和 UnitsInStock 項 , 在智能感知中檢查 Allow Paging (分頁)標記是否被選上
?
在這些操作后 FormView 的代碼大概會成這樣
< asp : FormView ID ="LowStockedProductsInRed" runat ="server" DataKeyNames ="ProductID" ??? DataSourceID ="ObjectDataSource1" AllowPaging ="True" EnableViewState ="False"> ??????????? ??? < ItemTemplate > ??????? < b >Product:</b> ??????? < asp : Label ID ="ProductNameLabel" runat ="server" Text =' <%# Bind("ProductName") %>'> ??????? </ asp : Label >< br /> ??????? < b >Units In Stock:</b> ??????? < asp : Label ID ="UnitsInStockLabel" runat ="server" Text =' <%# Bind("UnitsInStock") %>'> ??????? </ asp : Label > ??? </ ItemTemplate > </ asp : FormView > |
?
注意 ItemTemplate 包含的代碼 :
·???????? 靜態 HTML – “Product:” 和 “Units In Stock:” 包含 <br /> 和 <b> 元素 .
·???????? Web 控件 – 兩個 Label 控件 , ProductNameLabel 和 UnitsInStockLabel .
·???????? 綁定表達式 – <%# Bind("ProductName") %> 和 <%# Bind("UnitsInStock") %> 表達式 , 綁定值到 Label 的 Text 屬性上
?
?
?
Step 2: 在 DataBound 事件處理中編碼確定數據的值
當 FormView 的標記完成后,下一步就是確定 UnitsInStock 的值是否小于等于 10, 這里和在 DetailView 中類似,先創建 DataBound 事件

圖 6: 創建 DataBound 事件處理
在事件中聲明 FormView 的 DataItem 屬性到 ProductsRow 實例中 , 確定 UnitsInPrice 的值并將對應的值用紅色字體顯示
protected void LowStockedProductsInRed_DataBound(object sender, EventArgs e) { ??? // Get the ProductsRow object from the DataItem property... ??? Northwind.ProductsRow product = (Northwind.ProductsRow)((System.Data.DataRowView)LowStockedProductsInRed.DataItem).Row; ??? if (!product.IsUnitsInStockNull() && product.UnitsInStock <= 10) ??? { ??????? // TODO: Make the UnitsInStockLabel ’s text red ??? } } |
?
?
Step 3: 在 FormView 的 ItemTemplate 中格式化 UnitsInStockLabel Label
最后一步就是要在 ItemTemplate 中 設置 UnitsInStockLabel 的樣式為紅色字體,在 ItemTempelete 中查找控件可以使用 FindControl(“controlID”) 方法
?
WebControlType someName = (WebControlType)FormViewID.FindControl("controlID"); |
?
對于我們這個例子我們可以用如下代碼來查找該 Label 控件
?
Label unitsInStock = (Label)LowStockedProductsInRed.FindControl("UnitsInStockLabel"); |
?
當我們找到這個控件時則可以修改其對應的 style 屬性,在 style.css 中已經有一個寫好的 LowUnitsInStockEmphasis 的 cSS Class , 我們通過下面的代碼將 cSS Class 設置到對應的屬性
?
??? protected void LowStockedProductsInRed_DataBound(object sender, EventArgs e) ??? { ??????? // Get the ProductsRow object from the DataItem property... ??????? Northwind.ProductsRow product = (Northwind.ProductsRow)((System.Data.DataRowView)LowStockedProductsInRed.DataItem).Row; ??????? if (!product.IsUnitsInStockNull() && product.UnitsInStock <= 10) ??????? { ??????????? Label unitsInStock = (Label)LowStockedProductsInRed.FindControl("UnitsInStockLabel"); ? ??????????? if (unitsInStock != null) ??????????? { ??????????????? unitsInStock.CssClass = "LowUnitsInStockEmphasis"; ??????????? } ??????? } ??? } |
注意 : 這種方式在 FormView 和 GridView 中也可以通過設置 TemplateFields 來達到同樣的效果,我們將在下一篇中討論 TemplateFields
圖 7 顯示 FormView 在當 UnitsInStock 大于 10 的情況,圖 8 則顯示小于等于 10 的情況
圖 7 : 在高于 10 的情況下,沒有值被格式化

圖 8 :小于等于 10 時,值用紅色字體顯示
?
?
用 GridView 的 RowDataBound 事件自定義格式化
前面我們討論了在 FormView 和 DetailsView 中實現數據綁定的步驟,現在讓我們回顧下
- DataBinding 事件觸發
- 數據綁定到數據綁定控件
- DataBound 事件觸發
對于 FormView 和 DetailsView 有效因為只需要顯示一個數據,而在 GridView 中,則要顯示所有數據,相對于前面三個步驟,步驟二有些不同
在步驟二中, GridView 列出所有的數據,對于某一個記錄將創建一個 GridViewRow 實例并綁定,對于每個添加到 GridView 中的 GridViewRow 兩個事件將會觸發 :
·???????? RowCreated – 當 GridViewRow 被創建時觸發
·???????? RowDataBound – 當前記錄綁定到 GridViewRow 時觸發 .
?
對于 GridView ,請使用下面的步驟
- DataBinding 事件觸發
- 數據綁定到數據綁定控件
對于每一行數據 ..
a.?????? 創建 GridViewRow
b.?????? 觸發 RowCreated 事件
c.?????? 綁定數據到 GridViewRow
d.?????? 觸發 RowDataBound 事件
e.?????? 添加 GridViewRow 到 Rows 集合
- DataBound 事件觸發
?
為了自定義格式化 GridView 單獨記錄,我們需要為 RowDataBound 事件創建事件處理,讓我們添加一個 GridView 到 CustomColors.aspx 中,并顯示 name, category, 和 price ,用 黃色背景 高亮那些價格小于 $10.00 的產品
?
Step 1: 在 GridView 中顯示產品信息
添加一個 GridView 到 FormView 的下方,設置 ID 為 HighlightCheapProducts . 我們之前已經設置了一個 ObjectDataSource 來獲取產品數據,現在我們綁定 GridView 到 ObjectDataSource . 之后,編輯 GridView 的綁定列包含產品的 name.categorie,price 屬性。完成之后 GridView 的代碼將會是 :
< asp : GridView ID ="HighlightCheapProducts" runat ="server" AutoGenerateColumns ="False" ??? DataKeyNames ="ProductID" DataSourceID ="ObjectDataSource1" EnableViewState ="False"> ??? < Columns > ??????? < asp : BoundField DataField ="ProductName" HeaderText ="Product" SortExpression ="ProductName" /> ??????? < asp : BoundField DataField ="CategoryName" HeaderText ="Category" ReadOnly ="True" SortExpression ="CategoryName" /> ??????? < asp : BoundField DataField ="UnitPrice" DataFormatString ="{0:c}" HeaderText ="Price" ??????????? HtmlEncode ="False" SortExpression ="UnitPrice" /> ??? </ Columns > </ asp : GridView > |
?
?
?
?
圖九顯示瀏覽器查看的結果
圖 9: GridView 顯示產品的 name, category, price
?
Step 2: 在 RowDataBound 的 事件處理中編碼確定數據對應的值
當 ProductsDataTable 綁定到 GridView , GridView 將會產生若干個 ProductsRow 。 GridViewRow 的 DataItem 屬性將會生成一個實際的 ProductRow 。在 GridView 的 RowDataBound 事件發生之后,為了確定 UnitsInStock 的值,我們需要創建 RowDataBound 的事件處理,在其中我們可以確定 UnitsInStock 的值并做相應的格式化
EventHandler 的創建過程和前面兩個一樣

圖 10 : 創建 GridView 的 RowDataBound 事件的事件處理
在后臺代碼里將會自動生成如下代碼
protected void HighlightCheapProducts_RowDataBound(object sender, GridViewRowEventArgs e) { } |
?
當 RowDataBound 事件觸發 , 第二個參數 GridViewRowEventArgs 中包含了對 GridViewRow 的引用,我們用如下的代碼來訪問 GridViewRow 中的 ProductsRow
??? protected void HighlightCheapProducts_RowDataBound(object sender, GridViewRowEventArgs e) ??? {??????? // Get the ProductsRow object from the DataItem property... ??????? Northwind.ProductsRow product = (Northwind.ProductsRow)((System.Data.DataRowView)e.Row.DataItem).Row;
???????
if (!product.IsUnitPriceNull() && product.UnitPrice < ??????? { ??????????? // TODO: Highlight the row yellow... ???????} ??? } |
當運用 RowDataBound 事件處理時, GridView 由各種類型不同的行組成,而事件發生針對所有的行類型 , GridViewRow 的類型可以由 RowType 屬性決定,可以是以下類型中的一種
·???????? DataRow – GridView 的 DataSource 中的一條記錄
·???????? EmptyDataRow – GridView 的 DataSource 顯示出來的某一行為空
·???????? Footer – 底部行; 顯示由 GridView 的 ShowFooter 屬性決定
·???????? Header – 頭部行 ; 顯示由 GridView 的 ShowHeader 屬性決定
·???????? Pager – GridView 的分頁,這一行顯示分頁的標記
·???????? Separator – 對于 GridView 不可用,但是對于 DataList 和 Reapter 的 RowType 屬性卻很有用,我們將在將來的文章中討論他們
當上面四種 (DataRow,?Pager Rows?Footer,?Header) 都不合適對應值時,將返回一個空的數據項 , 所以我們需要在代碼中檢查 GridViewRow 的 RowType 屬性來確定 :
?
protected void HighlightCheapProducts_RowDataBound(object sender, GridViewRowEventArgs e) { ??????? // Make sure we are working with a DataRow ??????? if (e.Row.RowType == DataControlRowType.DataRow) ??????? { ??????????? // Get the ProductsRow object from the DataItem property... ??????????? Northwind.ProductsRow product = (Northwind.ProductsRow)((System.Data.DataRowView)e.Row.DataItem).Row;
???????????
if (!product.IsUnitPriceNull() && product.UnitPrice < ??????????? { ??????????????? // TODO: Highlight row yellow... ??????? ????} ??????? } } |
?
Step 3: 用黃色高亮那些 UnitPrice 小于 $10.00 的行
我們需要訪問 GridViewID .Rows[index] 來訪問 index 對應的那一行, GridViewID .Rows[index].Cells[index] 來訪問某一單元格 . 然而當 RowDataBound 事件觸發時, GridViewRow 卻沒有添加到 Rows 集合中 , 因此我們不能在 RowDataBound 事件處理中通過當前 GridViewRow 實例
?
取而代之,我們可以通過 e.Row 來訪問。為了高亮某一行我們用下面的代碼
e.Row.BackColor = System.Drawing. Color .Yellow; |
我們還可以通過 cSSClass 取得同樣的效果 ( 推薦 )
??? protected void HighlightCheapProducts_RowDataBound(object sender, GridViewRowEventArgs e) ??? { ??????? // Make sure we are working with a DataRow ??????? if (e.Row.RowType == DataControlRowType.DataRow) ??????? { ??????????? // Get the ProductsRow object from the DataItem property... ??????????? Northwind.ProductsRow product = (Northwind.ProductsRow)((System.Data.DataRowView)e.Row.DataItem).Row;
???????????
if (!product.IsUnitPriceNull() && product.UnitPrice < ??????????? { ??????????????? e.Row.CssClass = "AffordablePriceEmphasis"; ??????????? } ??????? } ??? } |
圖 11: 所需要的行用高亮黃色顯示
?
?
?
總結
在本篇中我們演示了基于數據綁定來自定義格式化 GridView,?DetailsView,?FormView 的方法。為了完成這些,我們創建 DataBound 或者 RowDataBound 事件 , 為了訪問 DetailsView 或 FormView 的數據綁定,我們可以通過 DataItem 屬性。對于 GridView ,每個 GridViewRow 實例的 DataItem 屬性包含了綁定的數據 ( 在 RowDataBound 事件處理中可用 )
?
為了調整格式,我們可能需要訪問某一特定的行,在 GridView 和 DetailsView 中我們可以通過索引訪問,而在 FormView 中我們則需要用 FindControl("controlID") , 同時 FindControl("controlID") 通常都可以訪問 Web 控件 Tempelete 中的某個控件
?
在下一篇中我們將討論如何在 GridView 和 DetailsView 使用 Tempeletes, 還將討論另外一些自定義格式化的方法