棄用DataGrid,使用GridView結合DetailsView

本文討論ASP.NET 2.0 技術
• ASP.NET 2.0 GridView、FormView 和 DetailsView
• DataGrid 和 GridView 的差異
• 這些控件的編程接口
• 如何完成主/詳細視圖

示例代碼下載:
GridView.exe

更多相關文章可查閱本站:
(.Net企業開發)patterns & practices 企業程序庫
(.Net企業開發)企業程序庫(一)——緩存應用程序塊簡介
(.Net企業開發)企業程序庫(二)——配置應用程序塊簡介
(.Net企業開發)企業程序庫(三)——數據訪問應用程序塊
(.Net企業開發)企業程序庫(四)——加密應用程序塊簡介
(.Net企業開發)之企業程序庫(五)——異常處理應用程序塊簡介
(.Net企業開發)之企業程序庫(六)——日誌和規範應用程序塊簡介
(.Net企業開發)之企業程序庫(七)——安全應用程序塊
ASP.NET 2.0中的DataSource控件
使用ASP.NET 2.0中的GridView控件
在ASP.NET 2.0中使用頁面導航控件
詳細研究Asp.Net中的DataReader(附代碼)
Asp.Net中使用DataReader對象
ASP.NET 數據訪問類

    儘管有豐富、功能強大的編程接口,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。通過這些控件的組合,您能夠輕鬆地建立主/詳細視圖,而只需少量代碼,有時根本不需要代碼。

  DetailsView 控件
  DetailsView 控件與 GridView 控件相似,它使用完全相同的安裝機制。GridView 控件在一頁顯示多條記錄,而 DetailsView 控件一次只顯示一條記錄。

圖 9. 在 DetailsView 控件中顯示一條記錄

  因此,DetailsView 控件與 GridView 控件形成了很好的互補。將 DetailsView 連接到 GridView 可以更好地控制更新個別項目或插入新項目的方式和時機。
  FormView 控件
  使用上述配置步驟,我們還能夠爲 ASP.NET 的開發配置另一個新控件 — FormView 控件。FormView 控件支持非常靈活的 UI 佈局。下面的示例顯示使用 FormView 控件查看單個數據庫記錄。

圖 10. FormView ItemTemplate 輸出
  像 ItemTemplate 和 EditItemTemplate 這樣不同的模板用於查看和修改數據庫記錄,無需任何自定義代碼。

圖 11. FormView EditTemplate 輸出


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 月一期的 MSDN®Magazine 中詳細介紹了 ASP.NET 2.0 的這項流行的新功能。簡言之,一個數據源控件就是一組 Microsoft® .NET Framework 類,它有利於數據存儲和數據綁定控件之間的雙向綁定。現有的控件(如 DataGrid)以及新的數據綁定控件(如 GridView),儘管綁定能力不同,但都能綁定到一個數據源。
一個數據源控件代表了數據源的主要功能:選擇、插入、更新和刪除。數據源控件能代表任何數據源:從關係數據源庫到 XML 文件,從流數據到業務對象。如果簡要介紹能讓您想起 .NET 的託管提供程序,請參見圖 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;Integrated
   Security=SSPI;"
   updatecommand="Update employees SET
           firstname=@firstname, lastname=@lastname
           Where 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"
   filtere­xpression="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 數據工具箱的重大改進。

DetailsView  DataGrid   ImageField
(.Net企業開發)patterns & practices 企業程序庫
(.Net企業開發)企業程序庫(一)——緩存應用程序塊簡介
(.Net企業開發)企業程序庫(二)——配置應用程序塊簡介
(.Net企業開發)企業程序庫(三)——數據訪問應用程序塊
(.Net企業開發)企業程序庫(四)——加密應用程序塊簡介
(.Net企業開發)之企業程序庫(五)——異常處理應用程序塊簡介
(.Net企業開發)之企業程序庫(六)——日誌和規範應用程序塊簡介
(.Net企業開發)之企業程序庫(七)——安全應用程序塊
ASP.NET 2.0中的DataSource控件
使用ASP.NET 2.0中的GridView控件
在ASP.NET 2.0中使用頁面導航控件
詳細研究Asp.Net中的DataReader(附代碼)
Asp.Net中使用DataReader對象
ASP.NET 數據訪問類 
 
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章