摘要:了解 ASP.NET 用於顯示數據的三個控件: DataGrid、DataList 和 Repeater。 這些控件中的每一個都有獨特的特性以及相關的優點和缺點。 創建顯示數據的 ASP.NET 應用程序時,為這項工作選擇正確的控件非常重要。 正如將在本文中所看到的一樣,選擇使用 DataGrid、DataList 還是 Repeater,要權衡下面三個因素: 可用性、開發時間和性能。 (12 頁打印頁)
簡介
自從出現了像 Microsoft Active Server Pages (ASP) 這樣的簡單且基於腳本的 Web 編程技術以來,Web 開發又有了很大的發展。 傳統 ASP 中常見的大量枯燥、重復的編碼工作,在 Microsoft ASP.NET 中不復存在了。 例如,正如所有傳統 ASP 開發人員一度都知道的那樣,在傳統 ASP Web 頁面中顯示數據需要下面的偽代碼:
Create connection to the database
Populate an ADO Recordset with a SQL query
Display any header HTML needed
For Each Record in the Recordset
Print out the Recordset field(s) and associated HTML
Move to the next record
Next
Display any footer HTML needed
例如,要在 HTML <table> 中顯示記錄集的內容,開發人員則不得不為 <table> 標記 (tag) 生成 HTML 標記 (markup),然後循環遍歷記錄集中的每一條記錄,每次循環生成一個 <tr> 標記,以及許多 <td> 標記和要顯示的記錄集字段的值。 最後,在循環之後,開發人員需要生成結束 <table> 標記。
傳統 ASP 所要求的這種方法有一個很大的缺點: 它把 HTML 內容和 ASP Web 頁面的源代碼緊密集成在一起。 因為沒有分離代碼和 HTML 內容,所以更改 HTML 的內容及其困難,尤其是對不懂編程技術的圖形藝術家或 Web 設計者來說更是如此。 而且,因為檢索數據庫結果和生成它的內容都需要代碼,所以代碼和 HTML 內容的這種集成相對來說需要大量的代碼。
幸好,ASP.NET 提供了三個控件,使得在 ASP.NET Web 頁面中顯示數據絕對比傳統 ASP 所需的迭代方式簡單得多。 這三個控件是 DataGrid、DataList 和 Repeater,以後我將稱之為數據 Web 控件。 也許,如果您已經開發過 ASP.NET Web 頁面,那麼至少會對這三個控件中的一個有一些經驗。 通常,開發人員從學習 DataGrid 開始,這是因為 DataGrid 使用簡單以及它具有允許數據排序、分頁和編輯的功能。 但是,在 ASP.NET Web 頁面中顯示數據時,DataGrid 並不總是控件的最佳選擇。
在本文中,我們將研究這些數據 Web 控件中每個控件的獨特特性。 這些特性賦予每個數據 Web 控件許多優點和缺點。 因為每一個數據 Web 控件都有一些缺點,所以沒有可用於任何作業的“完美”控件。 決定使用哪個控件時,必須權衡這三個數據 Web 控件每一個的優點和缺點,然後再決定哪個控件是最合適的。
為了協助進行比較,研究每一個數據 Web 控件時,我們將著重於這三個衡量標准: 可用性(從 Web 訪問者的角度)、開發時間和性能。 我們首先快速浏覽一下這三個數據 Web 控件之間的相似性。 接下來我們將深入研究 DataGrid,然後研究 DataList,最後查看 Repeater。 對於每一個控件,我們將研究這些控件的功能,並討論它的功能集是如何影響這些衡量標准的。
返回頁首
數據 Web 控件之間的相似性
在研究數據 Web 控件之間的差異(這些差異使它們區別於其他控件)之前,先看一下它們的相似性。 從較高級別觀點來看,最基本的相似性是,DataGrid、DataList 和 Repeater都設計為了執行大致相同的操作: 顯示數據。 另一個相似性把數據綁定到數據 Web 控件所需的代碼。 具體地說,只需要下面兩行代碼:
dataWebControlID.DataSource = someDataSource
dataWebControlID.DataBind()
通常,賦給數據 Web 控件的 DataSource 屬性的 someDataSource 對象是一個 DataSet、SqlDataReader、OleDbDataReader 或一個集合(如 Array、ArrayList 或 System.Collections 命名空間中的其他某個類)。 但是,任何實現 IEnumerable 接口的對象都可以綁定到數據 Web 控件。
DataBind() 方法枚舉指定的 DataSource 中的記錄。 對於 DataSource 中的每一條記錄,都會創建一個項並追加到數據 Web 控件的 Items 集合中。 數據 Web 控件中的每一項都是一個類實例。 用於控件每一項的特定類取決於該數據 Web 控件。 例如,DataGrid 中的每一項都是 DataGridItem 類的一個實例,而 Repeater 中的每一項都是 RepeaterItem 類的一個實例。
每個數據 Web 控件會為它的每一項使用不同的類,因為是這些項呈現的方式決定了數據 Web 控件生成的 HTML 標記。 例如,DataGridItem 類是從 TableRow 類中派生的,這意味著每個 DataGridItem 都或多或少地呈現為一個表行。 這很有意義,因為 DataGrid 設計為在 HTML <table> 標記內以表格形式顯示數據,在 HTML <table> 中,每一項都呈現為單獨一行。 另一方面,Repeater 設計為允許對它的輸出進行完全自定義。 因此,RepeaterItem 類不從 TableRow 類中派生並不令人驚訝。
數據 Web 控件之間的另一個相似性是每個控件都能使用模板提供高度自定義的輸出。 DataList 和 Repeater 控件必須 使用模板指定它們的內容,而 DataGrid 則通過 TemplateColumn 列類型可以為特定的列選擇使用模板(我們將在下一節“研究 DataGrid Web 控件”中討論各種不同的 DataGrid 列類型)。
最後一個值得注意的是 DataGrid 和 DataList 控件是從 WebControl 類中派生的,而 Repeater 控件是從 Control 類中派生的。 WebControl 類包含許多美學方面的屬性,例如 BackColor、ForeColor、CssClass、BorderStyle 等。 這意味著如果使用 DataGrid 和 DataList,就可以通過它們從 WebControl 類中繼承的屬性指定樣式設置。 而 Repeater 沒有任何這樣的樣式屬性。 正如我們將在“深入研究 Repeater”一節中所討論的一樣,對 Repeater 輸出的任何可視設置都必須在 Repeater 的模板中指定。
返回頁首
研究 DataGrid Web 控件
DataGrid Web 控件是這三個數據 Web 控件中功能最多的,但是在自定義控件生成的實際 HTML 標記時,它又是最不靈活的。 呈現的 HTML 標記中的這種不靈活性,是由於 DataGrid 是設計用於使用 HTML <table> 以表格形式顯示數據所造成的。 因此,對於每一條綁定到 DataGrid 的記錄,都會創建一個單獨的表行(<tr>),對於要顯示的記錄中的每一個字段,都會創建一個單獨的表列(<td>)。
DataGrid 提供了許多功能,可極大地提高要顯示的數據的可用性。 例如,把 DataGrid 的 AllowSorting 屬性設置為 True 並添加一點源代碼,開發人員就可以把一個普通的 DataGrid 變成一個其數據可以由最終用戶排序的 DataGrid。 另外,再增加一點工作量,開發人員就能增強 DataGrid 的功能以允許數據分頁或數據的內聯編輯。 這些功能明顯增強了 DataGrid 的可用性。
除了在可用性方面得分很高,DataGrid 還提供了很短的開發時間。 要使用 DataGrid 開始在 ASP.NET Web 頁面中顯示數據,只需要把 DataGrid 添加到 Web 頁面中並編寫兩行必要的代碼: 第一行把數據綁定到 DataGrid 的 DataSource,第二行調用 DataGrid 的 DataBind() 方法。 顯然,隨著添加到 DataGrid 中的功能數量的增加,開發時間也增加了,但這只是把開發時間和其他數據 Web 控件進行比較。 假設您要允許對 Repeater 顯示的數據進行排序。 添加這樣的功能是一定可能的,但是與用 DataGrid 完成同樣的操作相比,這需要明顯多很多的時間和精力。
盡管 DataGrid 具有良好的可用性和開發時間得分,但是這個控件有兩個固有的缺點。 第一,正如前面所談到的,DataGrid 在對所呈現的 HTML 標記進行自定義方面的功能很有限。 是的,您可以自定義 DataGrid 的不同行和列的字體、顏色和邊框,但是事實仍然是,當 DataGrid 顯示數據時,結果將是一個 HTML <table>,DataSource 中的每一條記錄都對應其中一個 <tr>,每一個字段都對應其中一個 <td>。
具體地說,DataGrid 中的每一列都是一個從 DataGridColumn 類中派生的類實例。 有五個內置的 DataGrid 列類型:
• BoundColumn
• ButtonColumn
• EditColumn
• HyperLinkColumn
• TemplateColumn
每一個列類型都提供數據或提供某種允許用戶和 DataGrid 進行交互的接口。 例如,BoundColumn 以純文本顯示 DataSource 字段的值,而 HyperLinkColumn 則會顯示一個超級鏈接,其文字和 URL 部分可能是 DataSource 字段。 除了這些內置的列類型,通過創建 DataGridColumn 類的派生類,還可以創建自定義 DataGrid 列類型。 (有關創建一個用於擴展 BoundColumn 功能以限制顯示字符數的列的示例,請參閱 Creating a Custom DataGridColumn Class。)
有了這麼多的 DataGrid 列類型,可能就不理解為什麼 DataGrid 呈現的 HTML 標記不能進行高度自定義了。 要知道,雖然每一個 DataGrid 列類型在呈現時生成不同的 HTML,但是每一列都包含在一組 <td> 標記中,每一行都包含在一組 <tr> 標記中。 因此,即使可以用 TemplateColumn 自定義每一行的特定列的 HTML 輸出,而 DataGrid 仍然呈現為 HTML <table>,其中每一行使用一個 <tr>,每一列使用一個 <td> 。 DataGrid 的這種限制禁止了更多具有創造性的數據顯示。 例如,如果要在每一表行中顯示五條記錄,就不能使用 DataGrid,必須使用DataList 或 Repeater。 另外,如果要在除 <table> 之外的 HTML 標記中顯示數據,很遺憾,就不能使用 DataGrid 了。
DataGrid 第二個缺點是它的性能。 DataGrid 是這三個數據 Web 控件中性能最差的。 基於這一點,由 DataGrid - 特別是具有許多行的 DataGrids - 產生的 ViewState 可能會非常大。 如果使用 DataGrid 僅僅是為了顯示數據,則可以關閉 ViewState,但是,使用 DataGrid 的排序、分頁或編輯功能時,就不能這樣做了。
為了測試 DataGrid 的性能,我使用了 Microsoft 的免費 Web Application Stress Tool (WAST)。 在本文最後的“基准設置”一節中列出了精確的測試條件和 WAST 設置。 另外,測試使用的代碼也可在本文最後下載。
這個 Web Application Stress Tool 會向 Web 服務器發出一組特定的 URL 請求。 對於每一項測試,我都在一分鐘之內盡可能快地不斷請求一個 URL。 WAST 報告了許多性能衡量標准;我要關注的一個衡量標准是每秒請求數,它表明了 Web 服務器每秒能執行多少次 ASP.NET Web 頁面。
對於一個僅顯示數據的簡單 DataGrid,運行了兩個測試。 具體地說,DataGrid 顯示了來自 Northwinds 數據庫的 Customers 表(Customers 表總共包含 91 條記錄)的四個字段。 DataGrid 的 AutoGenerateColumns 屬性設置為 True。 第一項測試把 DataGrid 放在一個 Web 窗體( <form runat="server">)中,而第二項測試則沒有。 如果在窗體中放置一個控件而不把它的 EnableViewState 屬性顯式設置為 False,那麼該控件則會用 ViewState 保持它的狀態。 創建這個 ViewState 項可能是一個比較費時的過程,因此減少了可處理的總的每秒請求數,結果如圖 1 所示。
圖 1: DataGrid 的每秒請求數
正如我們將要在研究 DataList 和 Repeater 時看到的一樣,這兩個控件都提供了比 DataGrid 更好的性能。
返回頁首
分析 DataList
記得 DataGrid 將呈現為 HTML <table>,每一個 DataSource 記錄作為一個表行(<tr>),每一個記錄字段作為一個表列(<td>)。 有時,您可能想更多地控制數據的顯示。 例如,您可能想把數據顯示在 HTML <table> 中,但不是每行顯示一條記錄,而是每行顯示五條記錄。 或者,您根本不想把數據顯示在 <table> 標記中,而是想把每個元素顯示在一個 <span> 標記中。
DataList 放棄了 DataGrid 所采用的“列”概念。 相反,DataList 的顯示是通過模板 定義的。 利用模板,開發人員可以指定混合的 HTML 語法和數據綁定語法。 HTML 語法是標准的 HTML 標記;數據綁定語法是使用 <%# 和 %> 標記分隔的,用於從 DataSource 的記錄中產生用於構造給定 DataList 項的內容。 例如,下面的 ItemTemplate 將顯示 DataSource 的字段 CompanyName:
<asp:DataList runat="server" id="myDataList">
<ItemTemplate>
<%# DataBinder.Eval(Container.DataItem, "CompanyName") %>
</ItemTemplate>
</asp:DataList>
除了數據綁定語法,模板也可以包含 HTML 標記。 通過更新上面的模板,可以使 CompanyName 字段以粗體顯示,而使 ContactName 字段以非粗體顯示在 CompanyName 字段的下面:
<asp:DataList runat="server" id="myDataList">
<ItemTemplate>
<b><%# DataBinder.Eval(Container.DataItem, "CompanyName") %></b>
<br />
<%# DataBinder.Eval(Container.DataItem, "ContactName") %>
</ItemTemplate>
</asp:DataList>
對於 DataList 的 DataSource 中的每一條記錄,都要計算 ItemTemplate 的數據綁定語法。 數據綁定語法的輸出與 HTML 標記一起指定了為 DataList 項呈現的 HTML。 DataList 還支持其他六個模板,包括 ItemTemplate在內共有如下七個:
• AlternatingItemTemplate
• EditItemTemplate
• FooterTemplate
• HeaderTemplate
• ItemTemplate
• SelectedItemTemplate
• SeparatorTemplate
注意,DataGrid 的 TemplateColumn 僅支持四個模板: ItemTemplate、HeaderTemplate、FooterTemplate 和 EditItemTemplate。
默認情況下,DataList 將每一項都顯示為 HTML <table> 中的一行。 但是,通過設置 RepeatColumns 屬性,您可以指定表的每一行顯示多少個 DataList 項。 除了可以指定 HTML <table> 的每一行顯示多少個 DataList 項之外,還可以指定 DataList 的內容應該使用 <span> 標記顯示,而不是使用 <table> 標記。 DataList 的 RepeatLayout 屬性可以設置為 Table 或 Flow,表示 DataList 中的數據呈現在 HTML <table> 中還是 <span> 標記中。
利用模板以及 RepeatColumns 和 RepeatLayout 屬性,很明顯 DataList 比 DataGrid 允許對呈現的 HTML 標記進行更多的自定義。 這種增強了的自定義使得使用 DataList 能夠產生更為友好的數據顯示,因為 DataGrid 的“每一條 DataSource 記錄占用一個表行的單 HTML <table>”模型不可能總是用於顯示信息的最佳選擇。 但是,只研究比 DataGrid 改進了的自定義並不足以確定 DataList 的可用性;我們還必須比較 DataGrid 和 DataList 的排序、分頁和編輯功能。
使用 EditItemIndex 模板以及 EditCommand、UpdateCommand 和 CancelCommand 事件,DataList 可以支持內聯編輯。 但是,用 DataList 添加這樣的功能比用 DataGrid 花費的開發時間要長。 開發時間的差異是由於下面兩個原因:
• 通過 EditCommandColumn 列類型即可在 DataGrid 中創建的編輯/更新/取消按鈕,必須手動添加到 DataList 中,以及
• DataGrid BoundColumn 列類型自動使用 TextBox Web 控件作為編輯接口,而使用 DataList 時必須通過 EditItemTemplate 為要編輯的項顯式指定的編輯接口。
雖然用 DataList 進行內聯編輯不是很困難,但是 DataList 的數據排序、分頁和編輯卻很困難。 雖然一些靈活的編碼肯定能完成這樣的功能,但是向 DataList 中添加這樣的功能將花費相當多的開發時間。 因此,如果最終用戶能對數據進行排序和分頁是一個必需要求的話,那麼最好選擇 DataGrid 而不選擇 DataList。
DataList 的性能比 DataGrid 的性能好,當 DataList 位於 Web 窗體內時這一點更明顯。 圖 2 顯示了 Web Application Stress Tool 在 DataList 上的測試結果。
圖 2: DataList 的每秒請求數
正如圖 2 中的結果顯示的那樣,當 DataList 放置在 Web 窗體內時(因此導致該 Web 控件生成它的 ViewState),該 Web 控件要遠勝於 DataGrid。
返回頁首
深入研究 Repeater
在所有這三個數據 Web 控件中,Repeater Web 控件在呈現的 HTML 裡提供了最大的靈活性。 DataGrid 或 DataList 會在預設的 HTML 標記中自動包含開發人員指定的內容。與它們不同的是,Repeater 在呈現的時候將嚴格生成指定的 HTML 標記。 因此,如果不想用 HTML <table>或者一系列 <span> 標記顯示數據,而希望以其他方式顯示數據,就必須使用 Repeater 控件。
就像 DataList 一樣,使用 Repeater 時要用模板指定標記。 Repeater 包含下列五個模板:
• AlternatingItemTemplate
• FooterTemplate
• HeaderTemplate
• ItemTemplate
• SeparatorTemplate
HeaderTemplate 和 FooterTemplate 指定出現在綁定到 Repeater 的數據之前和之後的 HTML 標記。 AlternatingItemTemplate 和 ItemTemplate 指定用於呈現 Repeater 的 DataSource 中的每條記錄的 HTML 標記和數據綁定語法。 例如,假設您要把包含雇員信息的數據集綁定到 Repeater,該數據集的其中一個字段是 EmployeeName。 如果要在 Web 頁上以無序列表的形式顯示雇員列表,則可以使用如下 Repeater 語法:
<asp:Repeater runat="server" id="rptEmployees">
<HeaderTemplate>
<ul>
</HeaderTemplate>
<ItemTemplate>
<li><%# DataBinder.Eval(Container.DataItem, "EmployeeName") %></li>
</ItemTemplate>
<FooterTemplate>
</ul>
</FooterTemplate>
</asp:Repeater>
與 DataGrid 和 DataList 不同,Repeater 類不是從 WebControl 類派生的。 因此,Repeater 缺少 DataGrid 和 DataList 二者共有的樣式屬性。 這一點歸結起來無非是說,如果想對 Repeater 中所顯示數據進行格式設置,則必須在 HTML 標記中進行這樣的操作。 例如,在上面的例子中,如果想用粗體顯示雇員的姓名,則必須更改 ItemTemplate 以包含 HTML 粗體標記,就像下面這樣:
<ItemTemplate>
<li><b><%# DataBinder.Eval(Container.DataItem, "EmployeeName")
%></b></li>
</ItemTemplate>
然而對於 DataGrid 或 DataList,通過把控件的 ItemStyle-Font-Bold 屬性設置為 True,就能用粗體顯示文本了。
Repeater 缺少樣式屬性會大大增加開發的時間指標。 例如,假設決定使用 Repeater 顯示數據,這些數據需要以粗體、中間對齊且帶有特定背景色的特定字體顯示。 所有這些都要用幾個 HTML 標記指定,這些標記很快就會使 Repeater 的模板變得凌亂不堪。 這種凌亂會使以後對外觀進行更改變得困難得多,尤其是當其他人對該項目進行操作時,則不得不查看大量 HTML 語法。 將這一點與為 DataGrid 或 DataList 指定格式進行比較。 對於這兩個控件中的任何一個,都可以通過指定 DataGrid 或 DataList 的樣式屬性來使模板免於凌亂。 此外,可以用一些工具來自動設置 DataGrid 和 DataList 的樣式屬性,例如 Microsoft Visual Studio .NET 或 ASP.NET Web Matrix。
除了延長開發時間之外,Repeater 還缺少有助於支持分頁、編輯或數據編輯的內置功能。 由於缺少這些功能支持,Repeater 在可用性的評定中得分很低。 當然,如果 所有您感興趣的只是顯示數據,而不用帶任何別致的鈴聲或口哨聲,那麼 Repeater 的功能匮乏就不是主要缺點了。 我之所以強調“如果”一詞是因為,通常,Web 應用程序一旦進行了部署,用戶就會發現他們需要附加的功能,例如排序、分頁和編輯。
Repeater 有一個彌補性的品質(這並不令人吃驚),那就是性能。 Repeater 的性能比 DataList 的性能稍微好一點,比 DataGrid 的性能要好很多。圖 3 顯示了Repeater 每秒能處理的請求數,並與 DataGrid 和 DataList 進行了對比。
圖 3: Repeater 的每秒請求數
返回頁首
小結
在 ASP.NET Web 頁面中顯示數據時,很多開發人員都選擇他們最熟悉的數據 Web 控件,通常是 DataGrid。 但是這樣的盲目決定不夠明智,因為根本沒有通用的“最好的”數據 Web 控件。 決定為給定的 Web 頁使用哪個數據 Web 控件時,應該先就以下各種問題自己考慮一下,以確定哪個控件最適合手邊的任務。 您想允許用戶對數據進行排序嗎? 需要把數據用非 HTML <table> 的格式顯示嗎? 頁面會被大量訪問嗎,因而性能是一個關鍵的問題嗎?
因為 DataGrid 能允許最終用戶排序、分頁和編輯它的數據,所以這三個數據 Web 控件中 DataGrid Web 控件提供了最好的功能集。 因為使用 DataGrid 時只需要把它添加到 Web 頁面中並寫幾行代碼,所以 DataGrid 也是最簡單易用的數據 Web 控件。 但是,容易使用和強大的功能是要付出代價的,如性能的代價: DataGrid 是三個數據 Web 控件中效率最低的,特別是當把它放置在 Web 窗體中時。
通過使用模板,DataList 對顯示的數據外觀提供了比 DataGrid 更多的控制。 但是,使用模板通常比使用 DataGrid 的列類型需要更多的開發時間 DataList 還支持數據的內聯編輯,但是實現起來需要的工作量比 DataGrid 多。 遺憾的是,在 DataList 中提供分頁和排序支持不是一件簡單的事。 DataList 比 DataGrid 提供了更好的性能,從而彌補了這些缺少的內置功能。
最後,Repeater 控件允許對呈現的 HTML 標記進行完整和全面的控制。 對於 Repeater,生成的唯一 HTML 是模板中數據綁定語句的值和模板中指定的 HTML 標記,而不會生成象 DataGrid 和 DataList 那樣的“額外”HTML。 由於要求開發人員指定完整生成的 HTML 標記,所以通常 Repeater 需要的開發時間最長。 而且,Repeater 不提供內置編輯、排序或分頁支持。 但是,Repeater 的性能確實是這三個數據 Web 控件中最好的。 它的性能可與 DataList 相比,但明顯比 DataGrid 好。
祝大家編程愉快!