盡管有豐富、功能強大的編程接口,ASP.NET1.xDataGrid控件仍需要編寫大量自定義代碼來處理普通操作,如分頁、排序、編輯和刪除數據。例如,當用戶單擊以保存或取消更改時,DataGrid控件能夠引發事件但不提供更多的功能。如果要將更改存儲到持續媒介(如一個數據庫)之中,則必須自己處理UpdateCommand事件,檢索更改后的值,編寫一條SQL命令,然后從該處提交更新。
DataGrid控件限制普通數據操作的引發事件,因為它是一個數據源不可知的控件,能夠綁定到任何可枚舉的數據對象。執行數據操作(如更新或刪除)需要直接連接到一個特定的數據源。在ASP.NET1.x中,則通過編寫特定于應用程序的ADO.NET代碼解決這個問題的。
ASP.NET2.0改進了數據綁定體系結構,引入了新的系列組件(數據源對象)作為數據綁定控件與ADO.NET對象之間的橋梁。這些源對象提升了一個略為不同的編程模型,提供了新功能和新成員。您的ASP.NET2.0應用程序應該使用最新的網格控件—GridView,顯示數據報告。與之相似的DataGrid控件仍然支持,但DataGrid不能充分利用數據源組件的特定功能。
GridView控件是DataGrid的接替者,并從幾個方面擴展了后者的功能。首先,它完全支持數據源組件,能夠自動處理諸如分頁、排序和編輯等數據操作,前提是綁定的數據源對象支持這些操作。另外,GridView控件有一些比DataGrid優越的功能上的改進。特別是,它支持多個主鍵字段,公開了一些用戶界面的改進功能和一個處理與取消事件的新模型。
GridView附帶了一對互補的視圖控件:DetailsView和FormView。通過這些控件的組合,您能夠輕松地建立主/詳細視圖,而只需少量代碼,有時根本不需要代碼。
GridView與DataGrid
ASP.NET2.0中數據綁定控件的類層次結構比ASP.NET1.x中的更一致。在2.0版本中,所有控件無論有什么樣的實際實現過程和用戶界面特點,均從同一個基類(BaseDataBoundControl類)派生。圖1顯示新的類關系圖。DataGrid和其他1.x版本的控件(如Repeater和DataList)沒有包含在該關系圖中。這些現有控件的繼承樹與ASP.NET1.x的相同。特別是,Repeater繼承了WebControl,而DataList和DataGrid繼承了BaseDataList。如圖1所示,GridView是一個復合數據綁定控件,它與其他所有數據綁定控件(包括DropDownList、DetailsView和ListBox)共享一組方法和屬性。
圖1ASP.NET類關系圖
GridView和DataGrid控件的高級功能相似,但基礎卻不同。GridView盡可能地保留了DataGrid的對象模型,以便輕松地從現有頁面進行移植。但是,基于DataGrid的代碼與新的基于GridView的代碼不可能100%兼容。
DataGrid與GridView控件的另一個主要差異在于自適應用戶界面。與1.x版本的DataGrid不同的是,GridView也能在移動設備上顯示。換句話說,您能夠使用相同的用于桌面頁面的網格控件在移動設備上生成報告。2.0版本的DataGrid也能自適應地顯示,但是它的UI功能沒有GridView豐富。
在ASP.NET2.0中,改進后的DataGrid控件支持諸如主題和個性化等通用的控件功能。此外,新的DataGrid控件可由一個數據源控件填充。但要記住,綁定到數據源對象的DataGrid只能用于讀取數據。要實際修改底層數據源,仍然需要一些用戶定義的代碼。而GridView控件可以利用底層數據源的功能并自動刪除或更新記錄。注意,GridView控件也支持傳統的基于DataSource屬性和DataBind方法的綁定機制。盡管完全支持這種綁定機制,但是不鼓勵使用這樣的編程實踐方法。
GridView和數據源控件
那么,數據源控件是什么?我在2004年6月一期的MSDN?Magazine中詳細介紹了ASP.NET2.0的這項流行的新功能。簡言之,一個數據源控件就是一組Microsoft?.NETFramework類,它有利于數據存儲和數據綁定控件之間的雙向綁定。現有的控件(如DataGrid)以及新的數據綁定控件(如GridView),盡管綁定能力不同,但都能綁定到一個數據源。
一個數據源控件代表了數據源的主要功能:選擇、插入、更新和刪除。數據源控件能代表任何數據源:從關系數據源庫到XML文件,從流數據到業務對象。如果簡要介紹能讓您想起.NET的托管提供程序,請參見圖2。
圖2數據源控件、GridView和數據源
數據源控件可以位于一些.NET數據提供程序的上層,在數據綁定控件和數據源之間形成一個中間層。數據源控件也會公開一個提供基本操作的公共接口。一些數據綁定控件—特別是GridView控件,將這些命令與其他與數據有關的操作一起,綁定到適當的自動編輯。
數據源控件通過其屬性和方法,將綁定內容以一組命名的視圖形式公開。IDataSource接口提供從數據源檢索數據視圖的基本功能集,所有數據源控件都實現了這個接口。ASP.NET2.0提供一些內置數據源控件,如圖3所列。圖3列出的數據源控件屬于兩類:列表和分層組件。SiteMapDataSource和XmlDataSource組件是分層數據源控件,用于像TreeView和Menu控件這樣的分層組件。其他各種組件用于管理列表數據。
圖4中的代碼說明如何在一個示例頁面上將GridView和DataGrid綁定到同一個數據源控件。在ASP.NET2.0中,這是推薦的數據綁定方法。SqlDataSource控件的特點是一個ConnectionString屬性加上SelectCommand、UpdateCommand、InsertCommand和DeleteCommand屬性的任意組合。所有屬性都是字符串形式,并且引用帶有可選參數的命令文本:
<asp:SqlDataSourcerunat="server"
ID="MySource"
ConnectionString="SERVER=(local);
DATABASE=northwind;IntegratedSecurity=SSPI;"
SelectCommand="SELECT*FROMemployeesWHEREemployeeid>@MinID">
<SelectParameters>
<asp:ControlParameterName="MinID"
ControlId="EmpID"
PropertyName="Text"/>
</SelectParameters>
</asp:SqlDataSource>
每個數據源控件由唯一的ID表示。ID是連結數據綁定控件和數據源控件之間的紐帶。通過DataSourceId屬性將GridView綁定到一個數據源控件。例如,每當網格需要獲取數據時,就執行與SQLDataSource控件相關聯的SelectCommandSQL命令。當網格需要更新或刪除一條記錄時,就執行相應的UpdateCommand或DeleteCommandSQL命令。如果不存在這樣的命令,則引發一個異常。在內部,當用戶刪除或更新一條記錄時,GridView就像1.x版本的DataGrid一樣引發事件。但是與DataGrid不同的是,GridView為這些事件定義內部的處理程序。默認的處理程序檢索綁定數據源定義的命令來處理和執行這些操作。圖4說明,在保持網格顯示或更新數據的標記后無需編寫代碼。在更復雜的情況下,您可能需要編寫一些代碼。
圖5GridView和DataGrid
數據源控件和GridView控件通常用于無代碼數據綁定。圖5顯示圖4的代碼生成的輸出結果。
在ASP.NET2.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.NET1.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這樣的事件也不管用,因為如果不啟用回調,則不能引發這些事件。最后,切記回調驅動的分頁和排序機制需要使用MicrosoftInternetExplorer5.0及更高版本。
GridView事件
GridView控件使用的方法與我們熟知的DataBind方法不同。在ASP.NET2.0中,許多控件以及Page類本身使用的是Pre-load/Post-load事件對。控件生命周期中的關鍵操作被包裝在一對事件中,一個在操作發生前觸發,另一個在操作完成后立即觸發。GridView類也是這樣。圖8顯示的是新事件列表。使用事件來通告操作極大地增強了編程能力。例如,通過掛鉤RowUpdating事件,您能夠檢查新值的更新內容。您可能想在客戶端提供的值存留到下層數據存儲之前,通過HTML編碼來處理RowUpdating事件。這種簡單的技巧有助于避免惡意的腳本注入。
使用pre/post事件對使您能夠取消一個基于運行時條件而進行的事件。請看以下代碼片段:
voidPageIndexChanging(objectsender,GridViewPageEventArgse)
{
//Isthisthesensitivepage?(>4)
boolisSensitivePage=(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:boundfielddatafield="productname"headertext="Product"/>
<asp:checkboxfielddatafield="discontinued"
headertext="Discontinued"/>
<asp:buttonfieldbuttontype="Button"text="Buy"/>
<asp:hyperlinkfieldtext="MoreInfo..."
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:imagefielddatafield="photo"headertext="Picture"/>
圖10顯示活動的ImageField列,它位于Northwind雇員表的照片字段。有趣的是,ImageField通過ASP.NET2.0DynamicImage控件顯示來自數據庫和URL兩者的圖像。而且,在編輯模式下,ImageField列彈出一個Browse按鈕,用于定位要上載的位于本機的新文件。
圖10圖像字段列
Template列也受支持,所需的語法與ASP.NET1.x的DataGrid使用的相似:
<asp:templatefieldheadertext="Product">
<itemtemplate>
<b><%#Eval("productname")%></b><br/>
availablein<%#Eval("quantityperunit")%>
</itemtemplate>
</asp:templatefield>
有趣的是,ASP.NET2.0允許的數據綁定表達式的語法更簡潔。在ASP.NET1.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.NET1.x中嘗試過這項操作,您就可大概了解這項功能了。
圖11活動的可分頁、可排序網格
圖11顯示一個可分頁、可排序的網格。圖12顯示此網格的完整代碼。(值得注意的是,僅當需要標記列標頭來指示排序方向時才需要使用C#代碼。)因此,無需編寫代碼,排序和分頁就能十分正常地運行。通過DataSourceMode屬性控制SQLDataSource的數據檢索模型。可行的值類型是DataSet(默認值)和DataReader。當DataSourceMode為DataSet時,數據源控件可能會一直選擇性地緩存SELECT命令的結果。這使得GridView適應于豐富多樣的使用情境,其中控件可提供無代碼排序、篩選和分頁功能。默認情況下禁用緩存,因此它必須在數據源控件上啟用。
在內存中緩存數據能大大提高性能,但是數據會顯得有些脆弱。您必須權衡利弊,因為如果系統內存運行效率低,Cache對象會自動丟棄最少使用的數據。此外,在ASP.NET2.0中,SQLDataSource控件可能選擇性地建立與數據庫的自動依賴關系,以便立即檢測到數據變更。這確保了總是顯示最新的數據。有關數據源控件功能的更多信息,請參見我在前面提到的2004年6月發表的文章。當SQLDataSource控件檢索模型為DataReader時,檢索數據使用IDataReader對象,它是一個只進、只讀、流水游標。
編輯數據
DataGrid控件最大的缺點之一—相反卻是GridView控件最大的優點之一,是處理數據源更新的能力。當綁定數據源支持更新時,GridView能夠自動執行數據操作,從而提供真正的出盒解決方案。數據源控件通過一些布爾屬性(例如CanUpdate、CanDelete、CanSort等)提供這些功能。
對GridView控件而言,數據編輯意味著就地編輯和記錄刪除。如前所述,就地編輯指網格支持更改當前顯示記錄的功能。啟用GridView的就地編輯,需要啟動AutoGenerateEditButton布爾屬性:
<asp:gridviewrunat="server"id="MyGridView"
datasourceid="MySource"
autogenerateeditbutton="true">
&S226;&S226;&S226;
</asp:gridview>
當AutoGenerateEditButton屬性設置為真時,GridView顯示附加的一列,如圖13中最左邊一列。單擊一行的Edit按鈕將此行置于編輯模式下。當一行處于編輯模式下時,非只讀行的每個綁定字段將顯示適當的輸入控件,通常是一個TextBox。當您單擊更新時,GridView引發RowUpdating事件并檢查數據源的CanUpdate屬性。如果CanUpdate返回值為假,則引發一個異常。否則,在數據源對象的UpdateCommand屬性后創建和配置一個命令對象。
圖13GridView的Edit列
即使您對SQL的操作僅限于定義命令結構—只定義語句而讓控件來完成其他操作,也無需使用ADO.NET或擔心如何使用命令或連接。想在用戶單擊Update時保留更改,可編寫以下代碼:
<asp:sqldatasourcerunat="server"id="MySource"
connectionstring="SERVER=...;DATABASE=northwind;Integrated
Security=SSPI;"
updatecommand="UPDATEemployeesSET
firstname=@firstname,lastname=@lastname
WHEREemployeeid=@employeeid">
</asp:sqldatasource>
<asp:gridviewrunat="server"id="MyGridView"
DataSourceId="MySource"
DataKeyNames="employeeid"AutoGenerateEditButton="true">
&S226;&S226;&S226;
</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屬性的合法內容:
DELETEemployeesWHEREemployeeid=@employeeid請注意,如果由于特定于數據庫的約束而無法刪除記錄,刪除操作將失敗。例如,如果子記錄通過某種關系引用父記錄,父記錄將無法刪除。在這種情況下,引發一個異常。
GridView控件不自動支持向數據源插入數據。沒有這項功能完全是由于實現GridView不依賴于底層數據源的功能和特性。實際上,數據源對象提供一個CanInsert屬性并支持一個InsertCommand屬性。請注意,通過GridView和DetailsView控件的組合能夠實現這個功能,一會您就會了解到。
DetailsView控件
許多應用程序需要一次作用于一條記錄。在ASP.NET1.x中,沒有內置的功能支持這種情況。創建單條記錄視圖是可能的,但需要您自己編寫代碼。首先,您需要獲取記錄,然后,將字段綁定到數據綁定表單,選擇性地提供分頁按鈕來瀏覽記錄。我編寫了三個CuttingEdge列的安裝程序來解決這個問題—2002年4月、5月和6月。
當生成主/詳細視圖時,經常需要顯示單條記錄的內容。通常,用戶從網格中選擇一條主記錄,讓應用程序追溯所有可用字段。通過組合GridView和DetailsView,編寫少量代碼,就能夠生成有層次結構的視圖。
DetailsView控件能夠自動綁定到任何數據源控件,使用其數據操作集。控件能夠自動分頁、更新、插入和刪除底層數據源的數據項,只要數據源支持這些操作。多數情況下,建立這些操作無需編寫代碼,如下所示:
<asp:detailsviewrunat="server"id="det"
datasourceid="MySource"
autogenerateeditbutton="true"
autogenerateinsertbutton="true"
autogeneratedeletebutton="true"
allowpaging="true"
headertext="Employees">
<pagersettingsmode="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.NET2.0中,如果您想生成主/詳細視圖,則無需處理SelectedIndexChanged事件。您可以將一個GridView控件和一個DetailsView控件拖放到頁面上,將兩者綁定到一個數據源。生成無代碼的主/詳細視圖的技巧是,將詳細視圖控件綁定到當前選定記錄所代表的數據源,如下所示:
<asp:sqldatasourcerunat="server"id="MyDetailSource"
&S226;&S226;&S226;
selectcommand="SELECT*FROMcustomers"
filterexpression="customerid='@customerid'">
<filterparameters>
<asp:ControlParameterName="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:FormViewID="EmpDetails"runat="server"
DataSourceId="MySource"AllowPaging="true">
<ItemTemplate>
&S226;&S226;&S226;
</ItemTemplate>
<EditItemTemplate>
&S226;&S226;&S226;
</EditItemTemplate>
<InsertItemTemplate>
&S226;&S226;&S226;
</InsertItemTemplate>
</asp:FormView>
圖16說明一個使用FormView控件的頁面。Edit按鈕通過命令名Edit的<asp:Button>元素來添加。這將導致FormView從只讀模式轉換到編輯模式,使用定義過的EditItemTemplate顯示。New命令名將強制控件轉換為插入模式,顯示InsertItemTemplate的定義內容。最后,如果您將命令名為Delete的按鈕添加到項目模板中,用戶單擊它時,FormView將調用數據源的Delete命令。
圖16FormView控件
如何檢索數據來更新或插入一條記錄?您可以使用一個新的數據綁定關鍵字Bind,它是專門為雙向綁定而設計的:
Bind關鍵字像Eval一樣用于顯示數據,而且能在更新或插入一條記錄時檢索輸入值。此外,Bind對GridView和DetailsView使用的TemplateFields非常有用。
Bind將綁定控件屬性值存入一個值集合,FormView控件自動檢索和使用這個集合來組合插入或編輯命令的參數列表。傳遞到Bind的參數必須與數據容器的字段名匹配。例如,上一個代碼片斷中的文本框存放備注字段的值。最后,還要記住的是編輯和插入模板必須包含保存變更的按鈕。這是指普通的按鈕—用于保存的Update和Insert以及用于放棄操作的Cancel。
FormView事件的工作方式與DetailsView和GridView相同。因此,如果想處理像數據預處理或后處理(例如,填充下拉框)這樣更復雜的操作,您應該為ItemCommand、ItemInserting和ModeChanging之類的事件編寫適當的事件處理程序。
小結
數據綁定控件是大多數Web應用程序的必要組成部分。數據綁定控件應該簡單但功能強大。理想的情況是,它們應該以很少的單擊操作以及有限的代碼數量提供高級的功能。雖然ASP.NET2.0仍然在使用,但是其新一代的數據綁定控件滿足了這個需求。ASP.NET1.x數據綁定的主要缺點是需要為普通數據操作編寫過多的代碼。這一點已經隨著數據源對象和GridView控件的引入而解決了。DetailsView和FormView是對GridView的完美補充,代表了對ASP.NET1.x數據工具箱的重大改進。
DataGrid控件限制普通數據操作的引發事件,因為它是一個數據源不可知的控件,能夠綁定到任何可枚舉的數據對象。執行數據操作(如更新或刪除)需要直接連接到一個特定的數據源。在ASP.NET1.x中,則通過編寫特定于應用程序的ADO.NET代碼解決這個問題的。
ASP.NET2.0改進了數據綁定體系結構,引入了新的系列組件(數據源對象)作為數據綁定控件與ADO.NET對象之間的橋梁。這些源對象提升了一個略為不同的編程模型,提供了新功能和新成員。您的ASP.NET2.0應用程序應該使用最新的網格控件—GridView,顯示數據報告。與之相似的DataGrid控件仍然支持,但DataGrid不能充分利用數據源組件的特定功能。
GridView控件是DataGrid的接替者,并從幾個方面擴展了后者的功能。首先,它完全支持數據源組件,能夠自動處理諸如分頁、排序和編輯等數據操作,前提是綁定的數據源對象支持這些操作。另外,GridView控件有一些比DataGrid優越的功能上的改進。特別是,它支持多個主鍵字段,公開了一些用戶界面的改進功能和一個處理與取消事件的新模型。
GridView附帶了一對互補的視圖控件:DetailsView和FormView。通過這些控件的組合,您能夠輕松地建立主/詳細視圖,而只需少量代碼,有時根本不需要代碼。
GridView與DataGrid
ASP.NET2.0中數據綁定控件的類層次結構比ASP.NET1.x中的更一致。在2.0版本中,所有控件無論有什么樣的實際實現過程和用戶界面特點,均從同一個基類(BaseDataBoundControl類)派生。圖1顯示新的類關系圖。DataGrid和其他1.x版本的控件(如Repeater和DataList)沒有包含在該關系圖中。這些現有控件的繼承樹與ASP.NET1.x的相同。特別是,Repeater繼承了WebControl,而DataList和DataGrid繼承了BaseDataList。如圖1所示,GridView是一個復合數據綁定控件,它與其他所有數據綁定控件(包括DropDownList、DetailsView和ListBox)共享一組方法和屬性。

圖1ASP.NET類關系圖
GridView和DataGrid控件的高級功能相似,但基礎卻不同。GridView盡可能地保留了DataGrid的對象模型,以便輕松地從現有頁面進行移植。但是,基于DataGrid的代碼與新的基于GridView的代碼不可能100%兼容。
DataGrid與GridView控件的另一個主要差異在于自適應用戶界面。與1.x版本的DataGrid不同的是,GridView也能在移動設備上顯示。換句話說,您能夠使用相同的用于桌面頁面的網格控件在移動設備上生成報告。2.0版本的DataGrid也能自適應地顯示,但是它的UI功能沒有GridView豐富。
在ASP.NET2.0中,改進后的DataGrid控件支持諸如主題和個性化等通用的控件功能。此外,新的DataGrid控件可由一個數據源控件填充。但要記住,綁定到數據源對象的DataGrid只能用于讀取數據。要實際修改底層數據源,仍然需要一些用戶定義的代碼。而GridView控件可以利用底層數據源的功能并自動刪除或更新記錄。注意,GridView控件也支持傳統的基于DataSource屬性和DataBind方法的綁定機制。盡管完全支持這種綁定機制,但是不鼓勵使用這樣的編程實踐方法。
GridView和數據源控件
那么,數據源控件是什么?我在2004年6月一期的MSDN?Magazine中詳細介紹了ASP.NET2.0的這項流行的新功能。簡言之,一個數據源控件就是一組Microsoft?.NETFramework類,它有利于數據存儲和數據綁定控件之間的雙向綁定。現有的控件(如DataGrid)以及新的數據綁定控件(如GridView),盡管綁定能力不同,但都能綁定到一個數據源。
一個數據源控件代表了數據源的主要功能:選擇、插入、更新和刪除。數據源控件能代表任何數據源:從關系數據源庫到XML文件,從流數據到業務對象。如果簡要介紹能讓您想起.NET的托管提供程序,請參見圖2。

圖2數據源控件、GridView和數據源
數據源控件可以位于一些.NET數據提供程序的上層,在數據綁定控件和數據源之間形成一個中間層。數據源控件也會公開一個提供基本操作的公共接口。一些數據綁定控件—特別是GridView控件,將這些命令與其他與數據有關的操作一起,綁定到適當的自動編輯。
數據源控件通過其屬性和方法,將綁定內容以一組命名的視圖形式公開。IDataSource接口提供從數據源檢索數據視圖的基本功能集,所有數據源控件都實現了這個接口。ASP.NET2.0提供一些內置數據源控件,如圖3所列。圖3列出的數據源控件屬于兩類:列表和分層組件。SiteMapDataSource和XmlDataSource組件是分層數據源控件,用于像TreeView和Menu控件這樣的分層組件。其他各種組件用于管理列表數據。
圖4中的代碼說明如何在一個示例頁面上將GridView和DataGrid綁定到同一個數據源控件。在ASP.NET2.0中,這是推薦的數據綁定方法。SqlDataSource控件的特點是一個ConnectionString屬性加上SelectCommand、UpdateCommand、InsertCommand和DeleteCommand屬性的任意組合。所有屬性都是字符串形式,并且引用帶有可選參數的命令文本:
<asp:SqlDataSourcerunat="server"
ID="MySource"
ConnectionString="SERVER=(local);
DATABASE=northwind;IntegratedSecurity=SSPI;"
SelectCommand="SELECT*FROMemployeesWHEREemployeeid>@MinID">
<SelectParameters>
<asp:ControlParameterName="MinID"
ControlId="EmpID"
PropertyName="Text"/>
</SelectParameters>
</asp:SqlDataSource>
每個數據源控件由唯一的ID表示。ID是連結數據綁定控件和數據源控件之間的紐帶。通過DataSourceId屬性將GridView綁定到一個數據源控件。例如,每當網格需要獲取數據時,就執行與SQLDataSource控件相關聯的SelectCommandSQL命令。當網格需要更新或刪除一條記錄時,就執行相應的UpdateCommand或DeleteCommandSQL命令。如果不存在這樣的命令,則引發一個異常。在內部,當用戶刪除或更新一條記錄時,GridView就像1.x版本的DataGrid一樣引發事件。但是與DataGrid不同的是,GridView為這些事件定義內部的處理程序。默認的處理程序檢索綁定數據源定義的命令來處理和執行這些操作。圖4說明,在保持網格顯示或更新數據的標記后無需編寫代碼。在更復雜的情況下,您可能需要編寫一些代碼。

圖5GridView和DataGrid
數據源控件和GridView控件通常用于無代碼數據綁定。圖5顯示圖4的代碼生成的輸出結果。
在ASP.NET2.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.NET1.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這樣的事件也不管用,因為如果不啟用回調,則不能引發這些事件。最后,切記回調驅動的分頁和排序機制需要使用MicrosoftInternetExplorer5.0及更高版本。
GridView事件
GridView控件使用的方法與我們熟知的DataBind方法不同。在ASP.NET2.0中,許多控件以及Page類本身使用的是Pre-load/Post-load事件對。控件生命周期中的關鍵操作被包裝在一對事件中,一個在操作發生前觸發,另一個在操作完成后立即觸發。GridView類也是這樣。圖8顯示的是新事件列表。使用事件來通告操作極大地增強了編程能力。例如,通過掛鉤RowUpdating事件,您能夠檢查新值的更新內容。您可能想在客戶端提供的值存留到下層數據存儲之前,通過HTML編碼來處理RowUpdating事件。這種簡單的技巧有助于避免惡意的腳本注入。
使用pre/post事件對使您能夠取消一個基于運行時條件而進行的事件。請看以下代碼片段:
voidPageIndexChanging(objectsender,GridViewPageEventArgse)
{
//Isthisthesensitivepage?(>4)
boolisSensitivePage=(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:boundfielddatafield="productname"headertext="Product"/>
<asp:checkboxfielddatafield="discontinued"
headertext="Discontinued"/>
<asp:buttonfieldbuttontype="Button"text="Buy"/>
<asp:hyperlinkfieldtext="MoreInfo..."
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:imagefielddatafield="photo"headertext="Picture"/>
圖10顯示活動的ImageField列,它位于Northwind雇員表的照片字段。有趣的是,ImageField通過ASP.NET2.0DynamicImage控件顯示來自數據庫和URL兩者的圖像。而且,在編輯模式下,ImageField列彈出一個Browse按鈕,用于定位要上載的位于本機的新文件。

圖10圖像字段列
Template列也受支持,所需的語法與ASP.NET1.x的DataGrid使用的相似:
<asp:templatefieldheadertext="Product">
<itemtemplate>
<b><%#Eval("productname")%></b><br/>
availablein<%#Eval("quantityperunit")%>
</itemtemplate>
</asp:templatefield>
有趣的是,ASP.NET2.0允許的數據綁定表達式的語法更簡潔。在ASP.NET1.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.NET1.x中嘗試過這項操作,您就可大概了解這項功能了。

圖11活動的可分頁、可排序網格
圖11顯示一個可分頁、可排序的網格。圖12顯示此網格的完整代碼。(值得注意的是,僅當需要標記列標頭來指示排序方向時才需要使用C#代碼。)因此,無需編寫代碼,排序和分頁就能十分正常地運行。通過DataSourceMode屬性控制SQLDataSource的數據檢索模型。可行的值類型是DataSet(默認值)和DataReader。當DataSourceMode為DataSet時,數據源控件可能會一直選擇性地緩存SELECT命令的結果。這使得GridView適應于豐富多樣的使用情境,其中控件可提供無代碼排序、篩選和分頁功能。默認情況下禁用緩存,因此它必須在數據源控件上啟用。
在內存中緩存數據能大大提高性能,但是數據會顯得有些脆弱。您必須權衡利弊,因為如果系統內存運行效率低,Cache對象會自動丟棄最少使用的數據。此外,在ASP.NET2.0中,SQLDataSource控件可能選擇性地建立與數據庫的自動依賴關系,以便立即檢測到數據變更。這確保了總是顯示最新的數據。有關數據源控件功能的更多信息,請參見我在前面提到的2004年6月發表的文章。當SQLDataSource控件檢索模型為DataReader時,檢索數據使用IDataReader對象,它是一個只進、只讀、流水游標。
編輯數據
DataGrid控件最大的缺點之一—相反卻是GridView控件最大的優點之一,是處理數據源更新的能力。當綁定數據源支持更新時,GridView能夠自動執行數據操作,從而提供真正的出盒解決方案。數據源控件通過一些布爾屬性(例如CanUpdate、CanDelete、CanSort等)提供這些功能。
對GridView控件而言,數據編輯意味著就地編輯和記錄刪除。如前所述,就地編輯指網格支持更改當前顯示記錄的功能。啟用GridView的就地編輯,需要啟動AutoGenerateEditButton布爾屬性:
<asp:gridviewrunat="server"id="MyGridView"
datasourceid="MySource"
autogenerateeditbutton="true">
&S226;&S226;&S226;
</asp:gridview>
當AutoGenerateEditButton屬性設置為真時,GridView顯示附加的一列,如圖13中最左邊一列。單擊一行的Edit按鈕將此行置于編輯模式下。當一行處于編輯模式下時,非只讀行的每個綁定字段將顯示適當的輸入控件,通常是一個TextBox。當您單擊更新時,GridView引發RowUpdating事件并檢查數據源的CanUpdate屬性。如果CanUpdate返回值為假,則引發一個異常。否則,在數據源對象的UpdateCommand屬性后創建和配置一個命令對象。

圖13GridView的Edit列
即使您對SQL的操作僅限于定義命令結構—只定義語句而讓控件來完成其他操作,也無需使用ADO.NET或擔心如何使用命令或連接。想在用戶單擊Update時保留更改,可編寫以下代碼:
<asp:sqldatasourcerunat="server"id="MySource"
connectionstring="SERVER=...;DATABASE=northwind;Integrated
Security=SSPI;"
updatecommand="UPDATEemployeesSET
firstname=@firstname,lastname=@lastname
WHEREemployeeid=@employeeid">
</asp:sqldatasource>
<asp:gridviewrunat="server"id="MyGridView"
DataSourceId="MySource"
DataKeyNames="employeeid"AutoGenerateEditButton="true">
&S226;&S226;&S226;
</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屬性的合法內容:
DELETEemployeesWHEREemployeeid=@employeeid請注意,如果由于特定于數據庫的約束而無法刪除記錄,刪除操作將失敗。例如,如果子記錄通過某種關系引用父記錄,父記錄將無法刪除。在這種情況下,引發一個異常。
GridView控件不自動支持向數據源插入數據。沒有這項功能完全是由于實現GridView不依賴于底層數據源的功能和特性。實際上,數據源對象提供一個CanInsert屬性并支持一個InsertCommand屬性。請注意,通過GridView和DetailsView控件的組合能夠實現這個功能,一會您就會了解到。
DetailsView控件
許多應用程序需要一次作用于一條記錄。在ASP.NET1.x中,沒有內置的功能支持這種情況。創建單條記錄視圖是可能的,但需要您自己編寫代碼。首先,您需要獲取記錄,然后,將字段綁定到數據綁定表單,選擇性地提供分頁按鈕來瀏覽記錄。我編寫了三個CuttingEdge列的安裝程序來解決這個問題—2002年4月、5月和6月。
當生成主/詳細視圖時,經常需要顯示單條記錄的內容。通常,用戶從網格中選擇一條主記錄,讓應用程序追溯所有可用字段。通過組合GridView和DetailsView,編寫少量代碼,就能夠生成有層次結構的視圖。
DetailsView控件能夠自動綁定到任何數據源控件,使用其數據操作集。控件能夠自動分頁、更新、插入和刪除底層數據源的數據項,只要數據源支持這些操作。多數情況下,建立這些操作無需編寫代碼,如下所示:
<asp:detailsviewrunat="server"id="det"
datasourceid="MySource"
autogenerateeditbutton="true"
autogenerateinsertbutton="true"
autogeneratedeletebutton="true"
allowpaging="true"
headertext="Employees">
<pagersettingsmode="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.NET2.0中,如果您想生成主/詳細視圖,則無需處理SelectedIndexChanged事件。您可以將一個GridView控件和一個DetailsView控件拖放到頁面上,將兩者綁定到一個數據源。生成無代碼的主/詳細視圖的技巧是,將詳細視圖控件綁定到當前選定記錄所代表的數據源,如下所示:
<asp:sqldatasourcerunat="server"id="MyDetailSource"
&S226;&S226;&S226;
selectcommand="SELECT*FROMcustomers"
filterexpression="customerid='@customerid'">
<filterparameters>
<asp:ControlParameterName="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:FormViewID="EmpDetails"runat="server"
DataSourceId="MySource"AllowPaging="true">
<ItemTemplate>
&S226;&S226;&S226;
</ItemTemplate>
<EditItemTemplate>
&S226;&S226;&S226;
</EditItemTemplate>
<InsertItemTemplate>
&S226;&S226;&S226;
</InsertItemTemplate>
</asp:FormView>
圖16說明一個使用FormView控件的頁面。Edit按鈕通過命令名Edit的<asp:Button>元素來添加。這將導致FormView從只讀模式轉換到編輯模式,使用定義過的EditItemTemplate顯示。New命令名將強制控件轉換為插入模式,顯示InsertItemTemplate的定義內容。最后,如果您將命令名為Delete的按鈕添加到項目模板中,用戶單擊它時,FormView將調用數據源的Delete命令。


圖16FormView控件
如何檢索數據來更新或插入一條記錄?您可以使用一個新的數據綁定關鍵字Bind,它是專門為雙向綁定而設計的:
Bind關鍵字像Eval一樣用于顯示數據,而且能在更新或插入一條記錄時檢索輸入值。此外,Bind對GridView和DetailsView使用的TemplateFields非常有用。
Bind將綁定控件屬性值存入一個值集合,FormView控件自動檢索和使用這個集合來組合插入或編輯命令的參數列表。傳遞到Bind的參數必須與數據容器的字段名匹配。例如,上一個代碼片斷中的文本框存放備注字段的值。最后,還要記住的是編輯和插入模板必須包含保存變更的按鈕。這是指普通的按鈕—用于保存的Update和Insert以及用于放棄操作的Cancel。
FormView事件的工作方式與DetailsView和GridView相同。因此,如果想處理像數據預處理或后處理(例如,填充下拉框)這樣更復雜的操作,您應該為ItemCommand、ItemInserting和ModeChanging之類的事件編寫適當的事件處理程序。
小結
數據綁定控件是大多數Web應用程序的必要組成部分。數據綁定控件應該簡單但功能強大。理想的情況是,它們應該以很少的單擊操作以及有限的代碼數量提供高級的功能。雖然ASP.NET2.0仍然在使用,但是其新一代的數據綁定控件滿足了這個需求。ASP.NET1.x數據綁定的主要缺點是需要為普通數據操作編寫過多的代碼。這一點已經隨著數據源對象和GridView控件的引入而解決了。DetailsView和FormView是對GridView的完美補充,代表了對ASP.NET1.x數據工具箱的重大改進。
更多文章、技術交流、商務合作、聯系博主
微信掃碼或搜索:z360901061

微信掃一掃加我為好友
QQ號聯系: 360901061
您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對您有幫助就好】元
