ASP.NET 2.0:棄用 DataGrid 吧,有新的網格控制項了!發布日期: 2005-1-13 | 更新日期: 2005-1-13
Dino Esposito
本文參考 2004 年 5 月的 ASP.NET 2.0 技術預覽版本。文中包含的所有資訊均有可能變更。
本文討論:
• |
ASP.NET 2.0 GridView、FormView 和 DetailsView |
• |
DataGrid 和 GridView 的差異 |
• |
這些控制項的編程介面 |
• |
如何完成主/詳細視圖 |
|
本文使用以下技術: ASP.NET、ASP.NET 2.0、C# 代碼下載: GridView.exe (124KB) |
本頁內容
|
GridView 與 DataGrid |
|
GridView 和資料來源控制項 |
|
GridView 物件模型 |
|
GridView 事件 |
|
顯示、排序和分頁 |
|
編輯資料 |
|
DetailsView 控制項 |
|
FormView 控制項 |
|
小結 |
儘管有豐富、功能強大的編程介面,ASP.NET 1.x DataGrid 控制項仍需要編寫大量自訂代碼來處理普通操作,如分頁、排序、編輯和刪除資料。例如,當使用者單擊以儲存或取消更改時,DataGrid 控制項能夠引發事件但不提供更多的功能。如果要將更改儲存到持續媒介(如一個資料庫)之中,則必須自己處理 UpdateCommand 事件,檢索更改後的值,編寫一條 SQL 命令,然後從該處提交更新。
DataGrid 控制項限制普通資料操作的引發事件,因為它是一個資料來源不可知的控制項,能夠綁定到任何可枚舉的資料對象。執行資料操作(如更新或刪除)需要直接連接到一個特定的資料來源。在 ASP.NET 1.x 中,則通過編寫特定於應用程式的 ADO.NET 代碼解決這個問題的。
ASP.NET 2.0 改進了資料繫結體繫結構,引入了新的系列組件(資料來源對象)作為資料繫結控制項與 ADO.NET 對象之間的橋樑。這些來源物件提升了一個略為不同的編程模型,提供了新功能和新成員。您的 ASP.NET 2.0 應用程式應該使用最新的網格控制項 — GridView,顯示資料報告。與之相似的 DataGrid 控制項仍然支援,但 DataGrid 不能充分利用資料來源組件的特定功能。
GridView 控制項是 DataGrid 的接替者,並從幾個方面擴充了後者的功能。首先,它完全支援資料來源組件,能夠自動處理諸如分頁、排序和編輯等資料操作,前提是繫結資料來源物件支援這些操作。另外,GridView 控制項有一些比 DataGrid 優越的功能上的改進。特別是,它支援多個主鍵欄位,公開了一些使用者介面的改進功能和一個處理與取消事件的新模型。
GridView 附帶了一對互補的視圖控制項:DetailsView 和 FormView。通過這些控制項的組合,您能夠輕鬆地建立主/詳細視圖,而只需少量代碼,有時根本不需要代碼。
GridView 與 DataGrid
ASP.NET 2.0 中資料繫結控制項的類階層比 ASP.NET 1.x 中的更一致。在 2.0 版本中,所有控制項無論有什麼樣的實際實現過程和使用者介面特點,均從同一個基類(BaseDataBoundControl 類)派生。圖 1 顯示新的類別關係圖。DataGrid 和其他 1.x 版本的控制項(如 Repeater 和 DataList)沒有包含在該關係圖中。這些現有控制項的繼承樹與 ASP.NET 1.x 的相同。特別是,Repeater 繼承了 WebControl,而 DataList 和 DataGrid 繼承了 BaseDataList。 1 所示,GridView 是一個複合資料繫結控制項,它與其他所有資料繫結控制項(包括 DropDownList、DetailsView 和 ListBox)共用一組方法和屬性。
圖 1 ASP.NET 類別關係圖
GridView 和 DataGrid 控制項的進階功能相似,但基礎卻不同。GridView 儘可能地保留了 DataGrid 的物件模型,以便輕鬆地從現有頁面進行移植。但是,基於 DataGrid 的代碼與新的基於 GridView 的代碼不可能 100% 相容。
DataGrid 與 GridView 控制項的另一個主要差異在於自適應使用者介面。與 1.x 版本的 DataGrid 不同的是,GridView 也能在行動裝置上顯示。換句話說,您能夠使用相同的用於案頭頁面的網格控制項在行動裝置上產生報告。2.0 版本的 DataGrid 也能自適應地顯示,但是它的 UI 功能沒有 GridView 豐富。
在 ASP.NET 2.0 中,改進後的 DataGrid 控制項支援諸如主題和個人化等通用的控制項功能。此外,新的 DataGrid 控制項可由一個資料來源控制項填充。但要記住,綁定到資料來源對象的 DataGrid 只能用於讀取資料。要實際修改底層資料來源,仍然需要一些使用者定義的代碼。而 GridView 控制項可以利用底層資料來源的功能並自動刪除或更新記錄。注意,GridView 控制項也支援傳統的基於 DataSource 屬性和 DataBind 方法的綁定機制。儘管完全支援這種綁定機制,但是不鼓勵使用這樣的編程實踐方法。
返回頁首
GridView 和資料來源控制項
那麼,資料來源控制項是什嗎?我在 2004 年 6 月一期的 MSDNMagazine 中詳細介紹了 ASP.NET 2.0 的這項流行的新功能。簡言之,一個資料來源控制項就是一組 Microsoft .NET Framework 類,它有利於資料存放區和資料繫結控制項之間的雙向繫結。現有的控制項(如 DataGrid)以及新的資料繫結控制項(如 GridView),儘管綁定能力不同,但都能綁定到一個資料來源。
一個資料來源控制項代表了資料來源的主要功能:選擇、插入、更新和刪除。資料來源控制項能代表任何資料來源:從關係資料來源庫到 XML 檔案,從流資料到業務對象。如果簡要介紹能讓您想起 .NET 的Managed 提供者,請參見圖 2。
圖 2 資料來源控制項、GridView 和資料來源
資料來源控制項可以位於一些 .NET 資料提供者的上層,在資料繫結控制項和資料來源之間形成一個中介層。資料來源控制項也會公開一個提供基本操作的公用介面。一些資料繫結控制項 — 特別是 GridView 控制項,將這些命令與其他與資料有關的操作一起,綁定到適當的自動編輯。
資料來源控制項通過其屬性和方法,將綁定內容以一組命名的視圖形式公開。IDataSource 介面提供從資料來源檢索資料檢視的準系統集,所有資料來源控制項都實現了這個介面。ASP.NET 2.0 提供一些內建資料來源控制項,如圖 3 所列。圖 3列出的資料來源控制項屬於兩類:列表和分層組件。SiteMapDataSource 和 XmlDataSource 組件是分層資料來源控制項,用於像 TreeView 和 Menu 控制項這樣的分層組件。其他各種組件用於管理列表資料。
圖 4 中的代碼說明如何在一個樣本頁面上將 GridView 和 DataGrid 綁定到同一個資料來源控制項。在 ASP.NET 2.0 中,這是推薦的資料繫結方法。SqlDataSource 控制項的特點是一個 ConnectionString 屬性加上 SelectCommand、UpdateCommand、InsertCommand 和 DeleteCommand 屬性的任意組合。所有屬性都是字串形式,並且引用帶有選擇性參數的命令文本:
<asp:SqlDataSource runat="server"ID="MySource"ConnectionString="SERVER=(local);DATABASE=northwind;Integrated Security=SSPI;"SelectCommand="SELECT * FROM employees WHERE employeeid > @MinID"><SelectParameters><asp:ControlParameter Name="MinID"ControlId="EmpID"PropertyName="Text" /></SelectParameters></asp:SqlDataSource>
每個資料來源控制項由唯一的 ID 表示。ID 是連結資料繫結控制項和資料來源控制項之間的紐帶。通過 DataSourceId 屬性將 GridView 綁定到一個資料來源控制項。例如,每當網格需要擷取資料時,就執行與 SQLDataSource 控制項相關聯的 SelectCommand SQL 命令。當網格需要更新或刪除一條記錄時,就執行相應的 UpdateCommand 或 DeleteCommand SQL 命令。如果不存在這樣的命令,則引發一個異常。在內部,當使用者刪除或更新一條記錄時,GridView 就像 1.x 版本的 DataGrid 一樣引發事件。但是與 DataGrid 不同的是,GridView 為這些事件定義內部的處理常式。預設的處理常式檢索綁定資料來源定義的命令來處理和執行這些操作。圖 4說明,在保持網格顯示或更新資料的標記後無需編寫代碼。在更複雜的情況下,您可能需要編寫一些代碼。
圖 5 GridView 和 DataGrid
資料來源控制項和 GridView 控制項通常用於無代碼資料繫結。圖 5 顯示圖 4的代碼產生的輸出結果。
在 ASP.NET 2.0 中,除了 DataSource 和 DataMember,DataGrid 還公開了 DataSourceId 屬性。DataSourceId 屬性將 DataGrid 串連到同一頁面上定義的一個合法資料來源對象。但是,DataGrid 不提供與 GridView 同一層級的自動化操作。當使用者單擊以更新一條記錄時,DataGrid 引發 UpdateCommand 事件,而 GridView 除了引發 Updating 和 Updated 事件外,還檢索和執行資料來源更新命令,允許使用者自訂發送到資料來源控制項的資訊。
返回頁首
GridView 物件模型
GridView 與 DataGrid 的整體結果看起來相似。一些通用元素經過了重新命名,一些通用功能現在需要不同的文法。總之,如果熟悉 DataGrid 控制項,則可立即自如地運用 GridView。圖 6 詳盡列出了組成 GridView 的新元素(請注意,其中一些元素,如 DetailLinkStyle,僅用於在行動裝置上顯示網格)。行元素通過 Rows 集合中的 GridViewRow 類產生的執行個體進行顯示。GridViewRow 類映射到 DataGridItem 類,而 Rows 明確替代了 DataGrid 的項目集合。行類型由 DataControlRowType 枚舉表示,用來指示位置和角色(例如,頁尾、頁首、頁導航和資料行)。GridView 還引入一個新概念 — 行元素狀態。該行狀態由 DataControlRowState 標記的枚舉值表示 — 通常值是 Edit,可選值為 Insert 和 Selected。有趣的是,這兩類枚舉恰巧由所有資料檢視控制項(GridView、DetailsView 和 FormView)共用。
除了引入符合自適應顯示的元素之外,GridView 僅有一個其他類型的新元素 — 空資料行。當 GridView 綁定到一個空資料來源時,會選擇性地顯示一些預設內容,為使用者提供反饋。在這種情況下顯示的內容依賴於新的空資料行元素的內容。可通過一個屬性 (EmptyDataText) 或一個模板 (EmptyDataTemplate) 設定該行的內容。
GridView 控制項的屬性主要分為三種類型:行為、可視設定和狀態。圖 7 列出 GridView 的一些屬性。請查看包括 EnableSortingAndPagingCallbacks、EmptyDataText 和 UseAccessibleHeader 在內的新屬性以及被重新命名或改編的屬性,後者實現了 DataGrid 已經支援的功能。
編程模型與按鈕列略有不同。在 ASP.NET 1.x 的 DataGrid 中,您不得不通過添加特定的列類型來建立一個 Edit 按鈕 — EditCommandColumn。如果要建立一個 Delete 或 Select 按鈕列,則必須添加通用的按鈕列並預定義一個命令名。GridView 對象則更一致、更簡潔。它基於三個新的布爾屬性:AutoGenerateEditButton、AutoGenerateDeleteButton 和 AutoGenerateSelectButton。當其中任何一個屬性設定為真時,網格中分別添加一個 Edit、Delete 或 Select 命令按鈕列。例如,當 AutoGenerateEditButton 屬性設定為真時,在網格中自動為每個資料行添加帶有 Edit 按鈕的一列。也可以手動添加這些按鈕,方法是在列集合中添加一個 CommandField 對象。Columns 屬性列出了列對象,這些對象很像 DataGrid 的 Columns 屬性列出的對象。根據客戶的反饋,其中也添加了幾個協助器屬性。特別是,您現在能夠為每個顯示行儲存多個索引值。實際上,DataGrid 的 DataKeyField 字串屬性已經擴充為一個欄位名數組。新的屬性命名為 DataKey,用於儲存由欄位名組成的一個字串數組,這個字串數組唯一標識一個資料行。DataKey 是特定行的值的相應數組。它返回 DataKey 對象的集合。每個 DataKey 對象包含一個鍵名值,DataKey 的 DataKey 對象數量與 GridView 的顯示行數相同。
SortDirection 和 SortExpression 跟蹤當前的網格排序。這些屬性用於在內部實現自動翻轉排序,標記網格當前排序次序。每個對象的 PagerSettings 組包含配置使用者介面、行為和頁導航位置的所有屬性。現在,頁導航支援的導航模式不但包括首行和尾行,還包括下一行和上一行。
GridView 控制項也能夠使用一個基於回調的輕量型機制來進行排序和分頁。您可以通過設定 EnableSortingAndPagingCallbacks 布爾屬性來開啟和關閉此功能。當單擊排序或分頁連結來啟用回調時,GridView 請求排序資料或下一頁,不回傳可視頁面。(這裡發生了一個往返過程,但是無頁面重新整理,因此您不知道。)請注意,這個功能有個警告:啟用 GridView 中的選項時,新頁面保留當前選定的索引。如果有與之相關聯的詳細資料頁面,那麼選定的內容將失去同步。處理類似 PageIndexChanging 這樣的事件也不管用,因為如果不啟用回調,則不能引發這些事件。最後,切記回調驅動的分頁和排序機制需要使用 Microsoft Internet Explorer 5.0 及更高版本。
返回頁首
GridView 事件
GridView 控制項使用的方法與我們熟知的 DataBind 方法不同。在 ASP.NET 2.0 中,許多控制項以及 Page 類本身使用的是 Pre-load/Post-load 事件對。控制項生命週期中的關鍵操作被封裝在一對事件中,一個在操作發生前觸發,另一個在操作完成後立即觸發。GridView 類也是這樣。圖 8 顯示的是新事件列表。使用事件來通告操作極大地增強了編程能力。例如,通過掛鈎 RowUpdating 事件,您能夠檢查新值的更新內容。您可能想在用戶端提供的值存留到下層資料存放區之前,通過 HTML 編碼來處理 RowUpdating 事件。這種簡單的技巧有助於避免惡意的指令碼注入。
使用 pre/post 事件對使您能夠取消一個基於運行時條件而進行的事件。請看以下程式碼片段:
void PageIndexChanging(object sender, GridViewPageEventArgs e){// Is this the sensitive page? (> 4)bool isSensitivePage = (e.NewPageIndex > 4);if (isSensitivePage && (User.Identity.Name != "username"))e.Cancel = true;return;}
取消是一個讀/寫布爾屬性,存在於所有從 CancelEventArgs 派生的事件參數類中。GridView 的許多事件參數類繼承了 CancelEventArgs,這意味著所有這些事件都能被取消。Cancel 屬性值在激發“pre”事件時通常設定為假。處理事件時,您能夠檢查一些條件,通過將 Cancel 屬性設定為真選擇取消事件。例如,剛才的程式碼片段在目前使用者未被授權查看索引大於 4 的頁面時,取消了轉換到新頁面的操作。
返回頁首
顯示、排序和分頁
一個網格通常用於顯示資料庫查詢的結果。使用 GridView 控制項顯示結果比以往更簡單。您只需建立一個資料來源對象,提供連接字串和查詢文本,為 GridView 的 DataSourceId 屬性分配資料來源 ID。運行時,GridView 自動綁定到資料來源,產生正確的資料列。在預設情況下,查詢的所有列均顯示在網格中。
像 DataGrid 控制項一樣,GridView 也支援在 Columns 集合中自訂欄欄位。如果只想顯示檢索到的資料欄位的一個子集,或只想自訂其顯示外觀,則可使用代表顯示資料列的對象來填充 Columns 集合。GridView 支援多種列類型,包括新的複選框和映像列類型:
<columns><asp:boundfield datafield="productname" headertext="Product" /><asp:checkboxfield datafield="discontinued"headertext="Discontinued" /><asp:buttonfield buttontype="Button" text="Buy" /><asp:hyperlinkfield text="More Info..."datanavigateurlfields="productid,discontinued"datanavigateurlformatstring="more.aspx?id={0}&disc={1}" /></columns>
圖 9 顯示的活動網格配置為使用代碼中列出的欄位。GridView 列類名與 DataGrid 介面中的相應類名略有不同。尾碼“column”基本被替換成尾碼“field”。除了名字的更改,與列類匹配的行為幾乎相同。一些新的列類型使您不必經常使用模板。例如,CheckBoxField 列通過一個複選框顯示特定的資料欄位,而改進的 HyperLinkField 列提供了期待已久的功能 — 支援多個 URL 參數。正如剛才的程式碼片段所示,DataNavigateUrlFields 屬性接收了一個以逗號分隔的欄位名列表,並將其合并到 DataNavigateUrlFormatString 屬性的文本中。
圖 9 帶有作用欄位的 GridView
請注意 ButtonField 與 CommandField 之間的差異。兩列都向網格的使用者介面添加了一個按鈕,但是 CommandField 用於顯示命令按鈕來執行選擇、編輯、插入或刪除操作。ButtonField 只是代表作為按鈕顯示的欄位。最後,GridView 能夠通過 ImageField 列類型內嵌影像。
<asp:imagefield datafield="photo" headertext="Picture" />
圖 10 顯示活動的 ImageField 列,它位於 Northwind 僱員表的照片欄位。有趣的是,ImageField 通過 ASP.NET 2.0 DynamicImage 控制項顯示來自資料庫和 URL 兩者的映像。而且,在編輯模式下,ImageField 列彈出一個 Browse 按鈕,用於定位要上傳的位於原生新檔案。
圖 10 映像欄位列
Template 列也受支援,所需的文法與 ASP.NET 1.x 的 DataGrid 使用的相似:
<asp:templatefield headertext="Product"><itemtemplate><b><%# Eval("productname")%></b> <br />available in <%# Eval("quantityperunit")%></itemtemplate></asp:templatefield>
有趣的是,ASP.NET 2.0 允許的資料繫結運算式的文法更簡潔。在 ASP.NET 1.x 中產生模板化的內容需要使用下列運算式: DataBinder.Eval(Container.DataItem, "fieldname")由於使用了一個更小的資料繫結機制,現在,您能夠避免使用 DataBinder 類中靜態 Eval 方法,而是調用 Page 類定義的新的 Eval 保護方法。您將計算的欄位名和方法傳遞給 Eval,決定當前的資料項目並通過 DataBinder.Eval 準備一個常規調用。
Eval 被聲明為 TemplateControl 類的一個保護方法,Page 和 UserControl 都從這個類派生。真正代表一個 .aspx 活動頁面的類是從 Page 派生的一個類的執行個體;因此,它能夠調入受保護的方法。ASCX 使用者控制項也是如此。
如果焦點是顯示純資料,則不需要像 GridView 這樣全新的網格控制項。當然,現在您只需少量代碼或不需要編碼就能將資料來源控制項綁定到 GridView,但是單憑這點就有必要替換 DataGrid 嗎?如果答案是否定的,請考慮排序和分頁。
在 GridView 控制項中,只需通過開啟 AllowPaging 和 AllowSorting 屬性就能啟用自動翻轉排序和分頁功能。如果在 ASP.NET 1.x 中嘗試過這項操作,您就可大概瞭解這項功能了。
圖 11 活動的可分頁、可排序網格
圖 11 顯示一個可分頁、可排序的網格。圖 12 顯示此網格的完整代碼。(值得注意的是,僅當需要標記列標題來指示排序方向時才需要使用 C# 代碼。)因此,無需編寫代碼,排序和分頁就能十分正常地運行。通過 DataSourceMode 屬性控制 SQLDataSource 的資料檢索模型。可行的實值型別是 DataSet(預設值)和 DataReader。當 DataSourceMode 為 DataSet 時,資料來源控制項可能會一直選擇性地緩衝 SELECT 命令的結果。這使得 GridView 適應於豐富多樣的使用情境,其中控制項可提供無代碼排序、篩選和分頁功能。預設情況下禁用緩衝,因此它必須在資料來源控制項上啟用。
在記憶體中快取資料能大大提高效能,但是資料會顯得有些脆弱。您必須權衡利弊,因為如果系統記憶體運行效率低,Cache 對象會自動丟棄最少使用的資料。此外,在 ASP.NET 2.0 中,SQLDataSource 控制項可能選擇性地建立與資料庫的自動依賴關係,以便立即檢測到資料變更。這確保了總是顯示最新的資料。有關資料來源控制項功能的更多資訊,請參見我在前面提到的 2004 年 6 月發表的文章。當 SQLDataSource 控制項檢索模型為 DataReader 時,檢索資料使用 IDataReader 對象,它是一個只進、唯讀、流水遊標。
返回頁首
編輯資料
DataGrid 控制項最大的缺點之一 — 相反卻是 GridView 控制項最大的優點之一,是處理資料來源更新的能力。當綁定資料來源支援更新時,GridView 能夠自動執行資料操作,從而提供真正的出盒解決方案。資料來源控制項通過一些布爾屬性(例如 CanUpdate、CanDelete、CanSort 等)提供這些功能。
對 GridView 控制項而言,資料編輯意味著就地編輯和記錄刪除。如前所述,就地編輯指網格支援更改當前顯示記錄的功能。啟用 GridView 的就地編輯,需要啟動 AutoGenerateEditButton 布爾屬性:
<asp:gridview runat="server" id="MyGridView"datasourceid="MySource"autogenerateeditbutton="true">•••</asp:gridview>
當 AutoGenerateEditButton 屬性設定為真時,GridView 顯示附加的一列, 13 中最左邊一列。單擊一行的 Edit 按鈕將此行置於編輯模式下。當一行處於編輯模式下時,非唯讀行的每個綁定欄位將顯示適當的輸入控制項,通常是一個 TextBox。當您單擊更新時,GridView 引發 RowUpdating 事件並檢查資料來源的 CanUpdate 屬性。如果 CanUpdate 傳回值為假,則引發一個異常。否則,在資料來源對象的 UpdateCommand 屬性後建立和配置一個命令對象。
圖 13 GridView 的 Edit 列
即使您對 SQL 的操作僅限於定義命令結構 — 只定義語句而讓控制項來完成其他動作,也無需使用 ADO.NET 或擔心如何使用命令或串連。想在使用者單擊 Update 時保留更改,可編寫以下代碼:
<asp:sqldatasource runat="server" id="MySource"connectionstring="SERVER=...;DATABASE=northwind;IntegratedSecurity=SSPI;"updatecommand="UPDATE employees SETfirstname=@firstname, lastname=@lastnameWHERE employeeid=@employeeid"></asp:sqldatasource><asp:gridview runat="server" id="MyGridView"DataSourceId="MySource"DataKeyNames="employeeid" AutoGenerateEditButton="true">•••</asp:gridview>
資料來源的 UpdateCommand 屬性被設定為 GridView 使用的 SQL 命令。您能夠使用所需的任意數量的參數。如果您採用一種特殊的命名規則,參數值也能夠自動解析。代表更新欄位的參數(例如 firstname)必須與網格列的 DataField 屬性名稱相匹配。用於標識工作記錄的 WHERE 子句中使用的參數必須與 DataKeyNames 屬性匹配,後者是顯示記錄的關鍵字段。最後,考慮這種情況:如果沒有定義 UpdateCommand,卻提交更改,那麼 CanUpdate 傳回值為假,並引發一個異常。RowUpdated 事件發出訊號通知更新命令結束。通過更新命令更新的行數可在 RowUpdated 事件參數的 AffectedRows 屬性中檢索。
GridView 自動收集輸入欄位的值,填充 name/value 對詞典,這個詞典指示了每個列欄位的新值。GridView 也公開一個 RowUpdating 事件,允許您修改正在傳遞到資料來源對象的值。此外,在相關資料來源上激發 Update 操作前,GridView 將自動調用 Page.IsValid。如果 Page.IsValid 傳回值為假,將取消操作。這對使用包括驗證程式在內的自訂編輯模板特別有用。
行刪除操作方式與此相似。下面的 SQL 命令是一個資料來源對象的 DeleteCommand 屬性的合法內容:
DELETE employees WHEREemployeeid=@employeeid請注意,如果由於特定於資料庫的約束而無法刪除記錄,刪除操作將失敗。例如,如果子記錄通過某種關係引用父記錄,父記錄將無法刪除。在這種情況下,引發一個異常。
GridView 控制項不自動支援向資料來源插入資料。沒有這項功能完全是由於實現 GridView 不依賴於底層資料來源的功能和特性。實際上,資料來源對象提供一個 CanInsert 屬性並支援一個 InsertCommand 屬性。請注意,通過 GridView 和 DetailsView 控制項的組合能夠實現這個功能,一會您就會瞭解到。
返回頁首
DetailsView 控制項
許多應用程式需要一次作用於一條記錄。在 ASP.NET 1.x 中,沒有內建的功能支援這種情況。建立單條記錄視圖是可能的,但需要您自己編寫代碼。首先,您需要擷取記錄,然後,將欄位綁定到資料繫結表單,選擇性地提供分頁按鈕來瀏覽記錄。我編寫了三個 Cutting Edge 列的安裝程式來解決這個問題 — 2002 年 4 月、5 月和 6 月。
當產生主/詳細視圖時,經常需要顯示單條記錄的內容。通常,使用者從網格中選擇一條主記錄,讓應用程式追溯所有可用欄位。通過組合 GridView 和 DetailsView,編寫少量代碼,就能夠產生有階層的視圖。
DetailsView 控制項能夠自動綁定到任何資料來源控制項,使用其資料操作集。控制項能夠自動分頁、更新、插入和刪除底層資料來源的資料項目,只要資料來源支援這些操作。多數情況下,建立這些操作無需編寫代碼,如下所示:
<asp:detailsview runat="server" id="det"datasourceid="MySource"autogenerateeditbutton="true"autogenerateinsertbutton="true"autogeneratedeletebutton="true"allowpaging="true"headertext="Employees"><pagersettings mode="NextPreviousFirstLast"firstpageimageurl="images/first.gif"lastpageimageurl="images/last.gif"nextpageimageurl="images/next.gif"previouspageimageurl="images/prev.gif" /></asp:detailsview>
DetailsView 控制項的使用者介面能夠通過使用資料欄位和類型進行自訂,其方式與 GridView 相似。DetailsView 不支援自訂模板,因為這項特殊的功能完全構造在新的 FormView 控制項中。DetailsView 具有一個命令欄,顯示 Edit、Delete 和 New 按鈕的任意組合。當您單擊 Edit 或 New 時,控制項顯示 Edit 或 Insert 模式,欄位內容顯示在文字框中。工作模式能通過 Mode 和 DefaultMode 屬性控制。
使用 DetailsView 控制項能很好地實現無需代碼的主/詳細視圖。除了 Edit 和 Delete 按鈕,GridView 控制項支援 Select 按鈕,它也是預定義的。通過設定 AutoGenerateSelectButton 屬性為真,您能為每一行啟用此按鈕。當使用者單擊此按鈕時,當前行輸入選定狀態,為 GridView 的 SelectedIndex 屬性分配從 0 開始的索引值。此外,GridView 控制項引發 SelectedIndexChanged 事件。應用程式可以掛鈎到這個事件,並執行自訂代碼。
在 ASP.NET 2.0 中,如果您想產生主/詳細視圖,則無需處理 SelectedIndexChanged 事件。您可以將一個 GridView 控制項和一個 DetailsView 控制項拖放到頁面上,將兩者綁定到一個資料來源。產生無代碼的主/詳細視圖的技巧是,將詳細視圖控制項綁定到當前選定記錄所代表的資料來源,如下所示:
<asp:sqldatasource runat="server" id="MyDetailSource"•••selectcommand="SELECT * FROM customers"filterexpression="customerid='@customerid'"><filterparameters><asp:ControlParameter Name="customerid"ControlId="masterGrid"PropertyName="SelectedValue" /></filterparameters></asp:sqldatasource>
資料來源對象的 FilterExpression 屬性為 SelectCommand 指定的基礎查詢定義 WHERE 子句。參數值能夠以多種方式指定,包括直接綁定一個控制項屬性。 對象將 @customerid 參數設定為主網格控制項的 SelectedValue 屬性儲存區的值。圖 14 的代碼顯示如何配置主網格控制項和詳細視圖控制項。圖 15 顯示活動頁面。請注意,無需程式碼來完成這些功能。
圖 15 活動主網格
返回頁首
FormView 控制項
FormView 是新的資料繫結控制項,使用起來像是 DetailsView 的模板化版本。它每次從相關資料來源中選擇一條記錄顯示,選擇性地提供分頁按鈕,用於在記錄之間移動。與 DetailsView 控制項不同的是,FormView 不使用資料控制項欄位,而是允許使用者通過模板定義每個項目的顯示。FormView 支援其資料來源提供的任何基本操作。
FormView 控制項是作為通常使用的更新和插入介面而設計的,它不能驗證資料來源架構,不支援進階編輯功能,比如外鍵欄位下拉。然而,使用模板來提供此功能很容易。FormView 和 DetailsView 有兩方面的功能差異。首先,FormView 控制項具有 ItemTemplate、EditItemTemplate 和 InsertItemTemplate 屬性,而 DetailsView 一個也沒有。其次,FormView 缺少命令列 — 將可用功能進行分組的工具列。與 GridView 和 DetailsView 控制項不同的是,FormView 沒有其自己預設的顯示布局。同時,它的圖形化布局完全是通過模板自訂的。因此,每個模板都包括特定記錄需要的所有命令按鈕。下列代碼片斷是在頁面中嵌入一個 FormView 的典型寫法。
<asp:FormView ID="EmpDetails" runat="server"DataSourceId="MySource" AllowPaging="true"><ItemTemplate>•••</ItemTemplate><EditItemTemplate>•••</EditItemTemplate><InsertItemTemplate>•••</InsertItemTemplate></asp:FormView>
圖 16 說明一個使用 FormView 控制項的頁面。Edit 按鈕通過命令名 Edit 的 <asp:Button> 元素來添加。這將導致 FormView 從唯讀模式轉換到編輯模式,使用定義過的 EditItemTemplate 顯示。New 命令名將強制控制項轉換為插入模式,顯示 InsertItemTemplate 的定義內容。最後,如果您將命令名為 Delete 的按鈕添加到項目模板中,使用者單擊它時,FormView 將調用資料來源的 Delete 命令。
圖 16 FormView 控制項
如何檢索資料來更新或插入一條記錄?您可以使用一個新的資料繫結關鍵字 Bind,它是專門為雙向繫結而設計的:
Bind 關鍵字像 Eval 一樣用於顯示資料,而且能在更新或插入一條記錄時檢索輸入值。此外,Bind 對 GridView 和 DetailsView 使用的 TemplateFields 非常有用。
Bind 將繫結控制項屬性值存入一個值集合,FormView 控制項自動檢索和使用這個集合來組合插入或編輯命令的參數列表。傳遞到 Bind 的參數必須與資料容器的欄位名匹配。例如,上一個代碼片斷中的文字框存放備忘欄位的值。最後,還要記住的是編輯和插入模板必須包含儲存變更的按鈕。這是指普通的按鈕 — 用於儲存的 Update 和 Insert 以及用於放棄操作的 Cancel。
FormView 事件的工作方式與 DetailsView 和 GridView 相同。因此,如果想處理像資料預先處理或後處理(例如,填充下拉框)這樣更複雜的操作,您應該為 ItemCommand、ItemInserting 和 ModeChanging 之類的事件編寫適當的事件處理常式。
返回頁首
小結
資料繫結控制項是大多數 Web 應用程式的必要組成部分。資料繫結控制項應該簡單但功能強大。理想的情況是,它們應該以很少的單擊操作以及有限的代碼數量提供進階的功能。雖然 ASP.NET 2.0 仍然在使用,但是其新一代的資料繫結控制項滿足了這個需求。ASP.NET 1.x 資料繫結的主要缺點是需要為普通資料操作編寫過多的代碼。這一點已經隨著資料來源對象和 GridView 控制項的引入而解決了。DetailsView 和 FormView 是對 GridView 的完美補充,代表了對 ASP.NET 1.x 資料工具箱的重大改進。
Dino Esposito 是一位在意大利工作的講師和顧問。他是 Programming ASP.NET 和 Introducing ASP.NET 2.0(均來自 Microsoft Press)的作者,他將大部分時間用於教授關於 ADO.NET 和 ASP.NET 的課程以及在會議上發表演講。可通過 cutting@microsoft.com 與 Dino 聯絡或訪問他的網路日記 http://weblogs.asp.net/despos。