1. 程式人生 > >在 DataList 中進行資料編輯與刪除操作概述

在 DataList 中進行資料編輯與刪除操作概述

 

簡介

資料插入、更新和刪除概述 教程中,我們已經就如何使用應用程式架構、ObjectDataSource 以及 GridView 、DetailsView 和FormView 控制元件進行插入、更新以及刪除資料操作進行了討論。使用 ObjectDataSource 以及這三種 Web 資料控制元件,實施簡單的資料修改介面非常容易,只需要在智慧標記中勾選一個複選框即可,不需要寫入程式碼。

然而不幸的是,DataList 中 缺少 GridView 控制元件所內建的編輯和刪除功能。這一功能的缺失,部分是由於 DataList 是來自 ASP.NET 的以前版本,在那時,宣告式資料來源控制元件和免程式碼資料修改頁面尚無法使用。雖然 ASP.NET 2.0 中的 Datalist 不具有與 GridView 這樣方便的資料修改功能,我們依然可以使用 ASP.NET 1.x 技術將這一功能囊括在內。該方法需要編寫少許程式碼,但是正如我們將會在本教程中看到的那樣,DataList 具有一些支援該過程的事件與屬性。

在本篇教程中,我們將瞭解怎樣建立一個 DataList 控制元件能支援對其底層資料進行修改和刪除。後面的教程將探討更多高階編輯與刪除場景,包括輸入欄位的確認、如何處理由資料訪問層或業務邏輯層產生的異常等。

注意:和 DataList 一樣,Repeater 控制元件也沒有現成的插入、更新或刪除功能。新增此類功能時,DataList 包含 Repeater 所不具備的一些屬性和事件,這些屬性和事件可以簡化這些功能的新增過程。因此,本教程以及後面與編輯和刪除內容相關的教程中,都將注意力集中在 DataList 方面。

步驟1 :建立編輯和刪除教程網頁

在我們就如何從 DataList 中更新和刪除資料進行探討之前,首先讓我們先花一些時間在我們的網站計劃中建立ASP.NET 頁面,在本教程以及接下來的幾個教程中,都會需要用到該網站工程。由增加一個新的、名為 EditDeleteDataList 的資料夾開始。接下來,將以下 ASP.NET 頁面新增到該資料夾,確保每個頁面與 Site.master 母版頁相關聯:

  • Default.aspx
  • Basics.aspx
  • BatchUpdate.aspx
  • ErrorHandling.aspx
  • UIValidation.aspx
  • CustomizedUI.aspx
  • OptimisticConcurrency.aspx
  • ConfirmationOnDelete.aspx
  • UserLevelAccess.aspx

圖1 :為教程新增 ASP.NET 頁面

和在其他資料夾中的情況一樣,EditDeleteDataList 資料夾中的 Default.aspx 也在自己的部分列出了多個教程。回想一下, SectionLevelTutorialListing.ascx 使用者控制元件提供本功能。因此,將使用者控制元件從 Solution Explorer 拖至頁面的設計檢視,完成使用者控制元件的新增。

圖2 :將SectionLevelTutorialListing.ascx 使用者控制元件新增至 Default.aspx

最後,將頁面作為條目新增到 Web.sitemap 檔案中。具體來說,將以下標記新增在帶有 DataList 和 Repeater <siteMapNode> 的主/ 明細報表之後:

  1. <siteMapNode
  2.     title="Editing and Deleting with the DataList"
  3.     description="Samples of Reports that Provide Editing and Deleting Capabilities"
  4.     url="~/EditDeleteDataList/Default.aspx" >
  5.     <siteMapNode
  6.         title="Basics"
  7.         description="Examines the basics of editing and deleting with the
  8.                      DataList control."
  9.         url="~/EditDeleteDataList/Basics.aspx" />
  10.     <siteMapNode
  11.         title="Batch Update"
  12.         description="Examines how to update multiple records at once in a
  13.                      fully-editable DataList."
  14.         url="~/EditDeleteDataList/BatchUpdate.aspx" />
  15.     <siteMapNode
  16.         title="Error Handling"
  17.         description="Learn how to gracefully handle exceptions raised during the
  18.                      data modification workflow."
  19.         url="~/EditDeleteDataList/ErrorHandling.aspx" />
  20.     <siteMapNode
  21.         title="Adding Data Entry Validation"
  22.         description="Help prevent data entry errors by providing validation."
  23.         url="~/EditDeleteDataList/UIValidation.aspx" />
  24.     <siteMapNode
  25.         title="Customize the User Interface"
  26.         description="Customize the editing user interfaces."
  27.         url="~/EditDeleteDataList/CustomizedUI.aspx" />
  28.     <siteMapNode
  29.         title="Optimistic Concurrency"
  30.         description="Learn how to help prevent simultaneous users from
  31.                      overwritting one another&apos;s changes."
  32.         url="~/EditDeleteDataList/OptimisticConcurrency.aspx" />
  33.     <siteMapNode
  34.         title="Confirm On Delete"
  35.         description="Prompt a user for confirmation when deleting a record."
  36.         url="~/EditDeleteDataList/ConfirmationOnDelete.aspx" />
  37.     <siteMapNode
  38.         title="Limit Capabilities Based on User"
  39.         description="Learn how to limit the data modification functionality
  40.                      based on the user&apos;s role or permissions."
  41.         url="~/EditDeleteDataList/UserLevelAccess.aspx" />
  42. </siteMapNode>

更新Web.sitemap 後,花點時間在瀏覽器中檢視教程網站。現在,左邊的選單包含有用於編輯、插入和刪除教程的各項。

圖3 :站點地圖現在包含用於 DataList 編輯和刪除教程的條目

步驟2 :探討用於更新和刪除資料的技術

使用 GridView 編輯和刪除資料是非常容易的,這是因為,實際上,GridView 和 ObjectDataSource 在一同工作。正如在資料插入、更新和刪除概述教程中所討論的那樣,當單擊某行的更新按鈕後, GridView 自動將其雙向資料繫結的欄位分配到其 ObjectDataSource 的 UpdateParameters 集合,然後呼叫該 ObjectDataSource 的 Update() 方法。

不幸的是,DataList 不提供這些中的任何一項內建功能。我們的責任是確保使用使用者值為ObjectDataSource 的引數賦值,並且確保呼叫其 Update() 方法。 DataList 提供瞭如下屬性和事件在這一方面協助我們:

  • — 當進行更新或刪除時,我們要有能力 唯一識別 DataList 中的每一項。將該屬性設定為已顯示資料的主鍵欄位。這樣做將用每個 DataList 專案的指定 DataKeyField 值為 DataList 的資料鍵集合賦值。
  • — 當單擊某個 Button 、LinkButton 或 ImageButton 且其 CommandName 屬性設定為“Edit” 時,將激發該事件。
  • — 當單擊某個 Button 、LinkButton 或者 ImageButton 且其 CommandName 屬性設定為“Cancel” 時,將激發該事件。
  • — 當單擊某個 Button 、LinkButton 或者 ImageButton 且其 CommandName 屬性設定為“Update” 時,將激發該事件。
  • — 當單擊某個 Button 、LinkButton 或 ImageButton 且其 CommandName 屬性設定為 “Delete” 時,將激發該事件。

利用這些屬性和事件,我們可以使用四種方法從 DataList 中對資料進行更新和刪除:

  1. 使用ASP.NET 1.x技術— DataList 早於 ASP.NET 2.0 和 ObjectDataSources 出現,可以完全通過程式設計對資料進行更新和刪除。該技術完全拋棄了ObjectDataSource ,需要在檢索資料以進行顯示以及當更新或刪除一個記錄時,從業務邏輯層中將資料與 DataList 直接繫結。
  2. 在頁面中使用單一ObjectDataSource控制元件,用於選擇、更新和刪除——雖然 DataList 沒有 GridView 所具備的內建編輯和刪除功能,但是這並不是說我們不能自己進行新增採用這種方式,我們可以像在 GridView 例項中那樣,使用 ObjectDataSource ,但是必須為 DataList 的 UpdateCommand 事件( 我們在這一事件中已設定 ObjectDataSource 引數並且呼叫其 Update() 方法) 建立一個 Event Handler 。
  3. 使用一個ObjectDataSource控制元件用於選擇,但是直接依靠BLL進行更新和刪除— 當使用選項2 時,我們需要在 UpdateCommand 事件中寫入些許程式碼,為引數賦值等。另外,我們可以堅持使用 ObjectDataSource 用於選擇,但是直接依靠 BLL 進行更新與刪除呼叫(如選項 1 中的做法)。依我看來,通過與 BLL 直接進行介面連線的方式進行資料更新,與通過分配 ObjectDataSource 的更新引數以及呼叫其 Update() 方法的方式進行更新相比,會產生更多的可讀程式碼。
  4. 通過多個ObjectDataSources使用宣告式方法— 前面的三種方式都需要編寫一些程式碼。如果您願意一直使用盡可能多的宣告式語句,在本文中有一個包括多個 ObjectDataSources 的最終選項。第一個ObjectDataSource 會從 BLL 中檢索資料,並將資料與 DataList 繫結。為了進行更新,需要新增另外一個 ObjectDataSource ,但是可以在 DataList 的 EditItemTemplate 模板中直接新增。為了將刪除支援包括在內,ItemTemplate 需要另外的 ObjectDataSource 。利用這一方法,這些內建 ObjectDataSource 使用控制元件引數,採用宣告的方式,將 ObjectDataSource 的引數與使用者輸入控制元件相互繫結(而不需要在 DataList 的 UpdateCommand Event Handler 中通過編碼對它們進行指定)。這一方式依然需要編碼一些程式碼 — 我們需要呼叫內建 ObjectDataSource 的 Update() 或者 Delete() 命令 — 但是與其它三種方式比起來,這一方式所要求的程式碼要少得多。這一方式的不足之處在於,多個 ObjectDataSources 會使得頁面變得散亂,對可讀性造成影響。

如果必須在這些方式中選擇一個的話,我寧願選擇選項 1 ,因為這一方式所提供的靈活性最強,並且 DataList 在已開始就被設計成是與這一形式相互相容的軟體。雖然 DataList 經過改進以便可以和 ASP.NET 2.0 資料來源控制元件一同工作,但是它並不具備“官方版” ASP.NET 2.0 Web 資料控制元件(GridView 、 DetailsView 和 FormView )所具有的可延伸性特點或特色選項 2 到選項 4 沒有任何優點。

本篇編輯與刪除教程以及後面的編輯與刪除教程將使用ObjectDataSource 用於顯示資料的檢索,並指示呼叫命令至 BLL 以進行更新和刪除資料(選項 3 )。

步驟3 :新增 DataList 並配置其ObjectDataSource

在本篇教程中,我們將建立一個 DataList ,以列出產品資訊,並針對每一種產品,為使用者提供可以對其名稱和價格進行編輯的功能以及完全刪除這一產品的功能。具體來說,我們將使用 ObjectDataSource 對顯示的記錄進行檢索,但是通過與 BLL 的直接介面連線進行更新與刪除操作。在我們處心積慮的想使 DataList 具備編輯與刪除功能之前,首先我們必須有一個頁面,以便在只讀介面上顯示產品。因為我們在前面的教程中已經分析了這些步驟,所以對於這些步驟我會一帶而過的進行說明。

首先,在 EditDeleteDataList 資料夾中開啟 Basics.aspx 頁面,同時從設計檢視中為這一頁面新增一個DataList 。接下來,從 DataList 的智慧標記中建立一個新的 ObjectDataSource 。因為我們正在處理產品資料,所以將其設定為使用 ProductsBLL 類。如果想對所有產品進行檢索,在 SELECT 選項卡中選擇 GetProducts() 方法。

圖4 :配置 ObjectDataSource 使用 ProductsBLL 類

圖5 :使用 GetProducts() 方法返回產品資訊

DataList 與 GridView 一樣,其設計未考慮新資料的插入操作;因此,從 INSERT 選項卡內的下拉選單中選擇 (None) 選項。 因為更新與刪除操作將通過 BLL 編碼執行,所以對於 UPDATE 與 DELETE 選項卡,也同樣選擇 (None) 。

圖6 :確認 ObjectDataSource 中的INSERT 、UPDATE 和 DELETE 選項卡 內的下拉列表已經設定為 (None)

配置 ObjectDataSource 後,單擊“完成”,返回至設計器。正如我們在先前的例項中看到的那樣,當完成 ObjectDataSource 配置後,Visual Studio 將會自動為下拉列表建立一個 ItemTemplate 模板,顯示每個資料欄位。用一個僅顯示產品名稱和價格的模板取代這一 ItemTemplate 模板。同時將 RepeatColumns 屬性設定為 2 。

注意 :正如在資料插入、更新和刪除概述教程中所討論的那樣,當使用ObjectDataSource 修改資料時,我們的構架要求必須將 OldValuesParameterFormatString 屬性從ObjectDataSource 的宣告式標記中移除(或者重置為其預設值 {0} ) 。然而在本篇教程中,我們僅在資料檢索中使用 ObjectDataSource 。因此,我們不需要修改 ObjectDataSource 的 OldValuesParameterFormatString 屬性值(雖然修改也不會造成什麼影響)。

在使用一個定製模板代替預設的DataList ItemTemplate 模板後,頁面中的宣告式標記應該與如下標記相似:

  1. <asp:DataList ID="DataList1" runat="server" DataKeyField="ProductID"
  2.     DataSourceID="ObjectDataSource1" RepeatColumns="2">
  3.     <ItemTemplate>
  4.         <h5>
  5.             <asp:Label runat="server" ID="ProductNameLabel"
  6.                 Text='<%# Eval("ProductName") %>'></asp:Label>
  7.         </h5>
  8.         Price: <asp:Label runat="server" ID="Label1"
  9.                     Text='<%# Eval("UnitPrice", "{0:C}") %>' />
  10.         <br />
  11.         <br />
  12.     </ItemTemplate>
  13. </asp:DataList>
  14. <asp:ObjectDataSource ID="ObjectDataSource1" runat="server"
  15.     SelectMethod="GetProducts" TypeName="ProductsBLL"
  16.     OldValuesParameterFormatString="original_{0}">
  17. </asp:ObjectDataSource>

花點時間在瀏覽器中檢視一下進度。如圖7 所示,DataList 以兩列顯示每個產品的產品名稱和單位價格。

圖7 :以兩列 DataList 顯示產品的名稱和價格

注意:DataList 有大量的屬性需要進行更新和刪除,這些屬性值都儲存在檢視狀態中。因此,在構建一個支援資料編輯與刪除的 DataList 時,啟用 DataList 的檢視狀態十分的重要。

敏感的讀者也許會記得,在建立可編輯的 GridView 、 DetailsView 以及 FormView 時,我們可以將檢視狀態關閉。這是因為 ASP.NET 2.0 Web 控制元件可以包括“控制狀態”,和檢視狀態一樣,這一狀態在整個回傳過程中始終保持狀態不變,這一點十分重要。

在 GridView 中關閉檢視狀態只會造成一些細小的狀態資訊被忽略,但是可以保持控制狀態(該狀態包括編輯和刪除操作所必須的狀態)。在 ASP.NET 1.x 時間框架中建立的 Datalist ,不需要利用控制狀態,因此必須啟用檢視狀態。有關更多關於控制狀態的資訊,以及與控制狀態和檢視狀態之間的區別有關的資訊,請參見控制狀態與檢視狀態部分。

步驟4 :新增編輯使用者介面

GridView 控制元件由欄位集(BoundFields 、CheckBoxFields 、TemplateFields 等)組成。這些欄位可以根據他們自己的模式調整自身的呈現標記。比如,當處於只讀模式時,BoundField 可以以文字顯示其資料欄位;當處於編輯模式時,BoundField 將呈現那些文字屬性被賦予資料欄位值的 Web 文字框控制元件。

另一方面,DataList 使用模板呈現自身的專案。只讀專案通過使用ItemTemplate 模板進行呈現,處於編輯模式下的專案通過 EditItemTemplate 模板進行呈現。此時,我們的 DataList 僅有一個 ItemTemplate 模板。若要支援專案範圍內的編輯功能,我們需要新增一個 EditItemTemplate 模板,該模板包含要為可編輯專案顯示的標記。在本教程中,我們將使用 Web 文字框控制元件來編輯產品的名稱和單位價格。

EditItemTemplate 模板既可以通過宣告的方式又可以通過設計器來建立(通過從 DataList 的智慧標記中選擇“編輯模板”)。要使用 Edit Templates 選項,首先在智慧標記中單擊“編輯模板”連結,然後從下拉列表中選擇 EditItemTemplate 模板專案。

圖8 :選擇 “與 DataList 的 EditItemTemplate 模板一同工作”

接下來,填寫“產品名稱” 一欄,和 “價格” 。然後從工具箱中將兩個文字框控制元件拖至設計器的 EditItemTemplate 模板介面中。將文字框的 ID 屬性設定為 ProductName 和 UnitPrice。

圖9 :為產品的名稱和價格新增文字框。

我們需要將相應的產品資料欄位值繫結至兩個文字框的文字屬性中。在文字框的智慧標記中,單擊 Edit DataBindings 連結,然後將適當的資料欄位與文字屬性相關聯,如圖 10 所示。

注意:當將 UnitPrice 資料欄位與價格文字框的文字欄位進行繫結時,您可以將其格式化為幣值 ({0:C}) 、通用數字 ({0:N}) 或保持其未格式化的狀態。

圖10 :將 ProductName 和 UnitPrice 資料欄位與文字框的文字屬性相繫結

注意,圖 10 中的 “編輯資料繫結” 對話方塊是如何將 “雙向資料繫結” 複選框排除在外的,當編輯 GridView 或 DetailsView 中的一個模板欄位或 FormView 中的模板時,“雙向資料繫結” 複選框就會出現。在資料插入和更新時,“雙向資料繫結”功能允許將鍵入到 Web 輸入控制元件中的數值自動分配至相應的 ObjectDataSource 插入引數或更新引數內。 DataList 不支援雙向資料繫結 — 這一點過一會我們會在本教程中看到,在使用者完成改變並準備進行資料更新時,我們將需要通過程式設計訪問文字框的文字屬性,並將他們的數值傳遞至 ProductsBLL 類內適當的 UpdateProduct 方法。

最後,我們需要將更新和取消按鈕新增至 EditItemTemplate 模板。正如我們在使用 DataList 和 Bulleted List 建立主/明細報表教程中所看到的那樣,當從 Repeater 或 DataList 中單擊已設定 CommandName 屬性的 Button 、LinkButton 、或 ImageButton 時,將觸發 Repeater 或DataList 的 ItemCommand 事件。對於 DataList 來說,如果 CommandName 屬性被設定為一個確定值,則可能觸發另外一個事件。 其中,特殊的 CommandName 屬性值包括:

  • “Cancel” — 引起 CancelCommand 事件
  • “Edit” — 引起 EditCommand 事件
  • “Update” — 引起 UpdateCommand 事件

請牢記,這些事件是除 ItemCommand 事件外的其他觸發事件。

在EditItemTemplate 中新增兩個 Web 按鈕控制元件,其中一個的 CommandName 設定為 “Update”,另外的一個設定為 “Cancel” 。在添加了這兩項 Web 按鈕控制元件後,設計器看起來類似如下圖片中的內容:

圖11 :在 EditItemTemplate 模板中新增更新與取消按鈕

EditItemTemplate 模板完成時,DataList 的宣告式標記應該與如下的標記相類似:

  1. <asp:DataList ID="DataList1" runat="server" DataKeyField="ProductID"
  2.     DataSourceID="ObjectDataSource1" RepeatColumns="2">
  3.     <ItemTemplate>
  4.         <h5>
  5.             <asp:Label runat="server" ID="ProductNameLabel"
  6.                 Text='<%# Eval("ProductName") %>' />
  7.         </h5>
  8.         Price: <asp:Label runat="server" ID="Label1"
  9.                     Text='<%# Eval("UnitPrice", "{0:C}") %>' />
  10.         <br />
  11.         <br />
  12.     </ItemTemplate>
  13.     <EditItemTemplate>
  14.         Product name:
  15.             <asp:TextBox ID="ProductName" runat="server"
  16.                 Text='<%# Eval("ProductName") %>' /><br />
  17.         Price:
  18.             <asp:TextBox ID="UnitPrice" runat="server"
  19.                 Text='<%# Eval("UnitPrice", "{0:C}") %>' /><br />
  20.         <br />
  21.         <asp:Button ID="UpdateProduct" runat="server"
  22.             CommandName="Update" Text="Update" /> 
  23.         <asp:Button ID="CancelUpdate" runat="server"
  24.             CommandName="Cancel" Text="Cancel" />
  25.     </EditItemTemplate>
  26. </asp:DataList>

步驟5 :在輸入編輯模式下新增管道

此時,DataList 具有一個通過自身 EditItemTemplate 模板進行定義的編輯介面;然而,在現階段還沒有一種方式可以允許使用者訪問我們的頁面以表示使用者想對產品資訊進行編輯。我們需要在每個產品中新增一個編輯按鈕,當單擊該編輯按鈕時,可以在編輯模式下對 DataList 專案進行呈現。首先可以通過設計器或採取宣告的方式,將一個編輯按鈕新增至 ItemTemplate 模板。一定要將編輯按鈕的 CommandName 屬性設定為“Edit”。

在新增完這一編輯按鈕後,花一些時間通過瀏覽器對頁面進行瀏覽。新增完畢後,每一個產品列表都應該包含一個編輯按鈕。

圖12 : 在 EditItemTemplate 模板中新增更新與取消按鈕

單擊按鈕 將 引起一個回傳,但是不要將產品列表引入編輯模式。為了使得產品可以編輯,我們需要:

  1. 將 DataList 的EditItemIndex屬性設定為剛單擊過的編輯按鈕的 DataListItem 的索引。
  2. 再次將資料與 DataList 進行繫結。當 DataList 經過再次呈現後,其 ItemIndex 與 DataList 的 EditItemIndex 相對應的 DataListItem 將會使用自身的 EditItemTemplate 模板進行呈現。

因為當單擊編輯按鈕後,將觸發 DataList 的EditCommand 事件,所以使用如下的程式碼建立一個EditCommand event handler :

  1. protected void DataList1_EditCommand(object source, DataListCommandEventArgs e)
  2. {
  3.     // Set the DataList's EditItemIndex property to the
  4.     // index of the DataListItem that was clicked
  5.     DataList1.EditItemIndex = e.Item.ItemIndex;
  6.     // Rebind the data to the DataList
  7.     DataList1.DataBind();
  8. }

EditCommand event handler 以 DataListCommandEventArgs 型別物件傳遞,作為其第二個輸入引數,該引數 包括一個 DataListItem 參考(該 DataListItem 的編輯按鈕被單擊)(e.Item) 。Event Handler 首先將 DataList 的 EditItemIndex 設定為可編輯 DataListItem 的專案索引,然後通過呼叫DataList 的 DataBind() 方法,將資料與 DataList 再次進行繫結。

在新增這一Event Handler 後,在瀏覽器中再次訪問該頁面。現在單擊編輯按鈕,就可以對所單擊的產品進行編輯(見圖 13 )。

圖13 :單擊編輯按鈕,使得產品變成可編輯狀態

步驟6:儲存使用者所做的改變

此時,單擊已編輯產品的更新或取消按鈕不會起任何作用;如果想要新增該功能,我們需要為 DataList 的 UpdateCommand 和 CancelCommand 事件建立 Event Handler 。首先建立 CancelCommand Event Handler ,當單擊已編輯產品的取消按鈕時,將執行該操作,它還會使 DataList 返回至編輯前的狀態。

要使 DataList 在只讀模式下呈現其所有的專案,我們需要:

  1. 將 DataList 的 EditItemIndex 屬性設定為不存在的 DataListItem 索引。因為 DataListItem 索引的起始值為 0 ,所以選擇 -1 是比較保險的選擇。
  2. 再次將資料與 DataList 進行繫結。因為不存在與 DataList 的 EditItemIndex 相對應的 DataListItem 專案索引,所以整個的 DataList 都將在一個只讀模式下進行呈現。

使用如下的Event Handler 程式碼就可以實現上述步驟:

  1. protected void DataList1_CancelCommand(object source, DataListCommandEventArgs e)
  2. {
  3.     // Set the DataList's EditItemIndex property to -1
  4.     DataList1.EditItemIndex = -1;
  5.     // Rebind the data to the DataList
  6.     DataList1.DataBind();
  7. }

新增完成之後,單擊取消按鈕就會將 DataList 返回至編輯前的狀態。

我們需要完成的最後一個Event Handler 是 UpdateCommand Event Handler 。該 Event Handler 需要:

  1. 通過編碼訪問由使用者輸入的產品名稱和價格,以及已編輯的產品的 ProductID 。
  2. 通過在 ProductBLL 類內呼叫合適的 UpdateProduct 過載來啟動更新程序。
  3. 將 DataList 的 EditItemIndex 屬性設定為不存在的 DataListItem 索引。因為 DataListItem 索引的起始值為 0 ,所以選擇 -1 是比較保險的選擇。
  4. 再次將資料與 DataList 進行繫結。因為不存在與 DataList 的 EditItemIndex 相對應的 DataListItem 專案索引,所以整個的 DataList 都將在一個只讀模式下進行呈現。

步驟 1 和步驟 2 負責對使用者所做出的改變進行儲存;在所做改變被儲存之後,步驟 3 和步驟 4 將 DataList 返回至編輯前的狀態,步驟 3 和步驟 4 與在 CancelCommand Event Handler 中所執行的步驟相同。

為了獲得已經更新的產品名稱和價格,我們需要使用 FindControl 方法,在EditItemTemplate 面板內通過編碼為 Web 文字框控制元件做附註。我們還需要獲得已編輯產品的 ProductID 值。我們最初將 ObjectDataSource 與 DataList 相互繫結時, Visual Studio 會將 DataList 的 DataKeyField 屬性從資料來源 (ProductID) 中分配給主鍵值。然後可以從 DataList 的 DataKeys 集合中檢索該值。花一些時間確保 DataKeyField 屬性確實被設定為 ProductID 。

以下的程式碼會實現四個步驟:

  1. protected void DataList1_UpdateCommand(object source, DataListCommandEventArgs e)
  2. {
  3.     // Read in the ProductID from the DataKeys collection
  4.     int productID = Convert.ToInt32(DataList1.DataKeys[e.Item.ItemIndex]);
  5.     // Read in the product name and price values
  6.     TextBox productName = (TextBox)e.Item.FindControl("ProductName");
  7.     TextBox unitPrice = (TextBox)e.Item.FindControl("UnitPrice");
  8.     string productNameValue = null;
  9.     if (productName.Text.Trim().Length > 0)
  10.         productNameValue = productName.Text.Trim();
  11.     decimal? unitPriceValue = null;
  12.     if (unitPrice.Text.Trim().Length > 0)
  13.         unitPriceValue = Decimal.Parse(unitPrice.Text.Trim(),
  14.             System.Globalization.NumberStyles.Currency);
  15.     // Call the ProductsBLL's UpdateProduct method...
  16.     ProductsBLL productsAPI = new ProductsBLL();
  17.     productsAPI.UpdateProduct(productNameValue, unitPriceValue, productID);
  18.     // Revert the DataList back to its pre-editing state
  19.     DataList1.EditItemIndex = -1;
  20.     DataList1.DataBind();
  21. }

從 DataKeys 集合中讀取已編輯產品的 ProductID ,將啟動 Event Handler 。接下來,將引用 EditItemTemplate 模板中的兩個文字框,他們的文字屬性儲存在本地變數、ProductNameValue 以及 unitPriceValue 中。我們使用 Decimal.Parse() 方法從 UnitPrice 文字框中讀取數值,這樣,如果輸入的數值中含有貨幣符號,依然可以轉換為十進位制數值。

注意:如果已指定了文字框的文字屬性值,那麼來自 ProductName 和 UnitPrice 文字框中的數值只會分配至 ProductNameValue 變數和 unitPriceValue 變數。否則,變數就會使用一個空值,其結果就是通過資料庫 NULL 值對資料進行更新。即,我們的程式碼將空字串轉換成了資料庫 NULL 值,該操作在 GridView 、 DetailsView 和 FormView 控制元件中是編輯介面的預設行為。

在讀取數值後,呼叫 ProductsBLL 類的 UpdateProduct 方法,傳遞產品名稱、價格以及 ProductID 。通過使用與在 CancelCommand Event Handler中幾乎相同的邏輯,將 DataList 返回至編輯前的狀態,該 Event Handler也就完成了。

隨著 EditCommand 、CancelCommand 和 UpdateCommand Event Handler 的完成,網站的訪問者就可以對一種產品的名稱和價格進行編輯了。圖 14-16 顯示了這一編輯操作的流程。

圖14 :當第一次訪問頁面時,所有的產品都處於只讀模式

圖15 :要更新某種產品的名稱或價格,單擊編輯按鈕

圖16 :更改數值後,單擊更新返回至只讀模式

步驟7 :新增刪除功能

在 DataList 中新增刪除功能的步驟與新增編輯功能的步驟類似。簡而言之,我們需要在ItemTemplate 中新增一個刪除按鈕,當單擊時:

  1. 通過 DataKeys 集合讀取相應產品的 ProductID。
  2. 通過呼叫 ProductsBLL 類的 DeleteProduct 方法,執行刪除操作。
  3. 將資料與 DataList 再次進行繫結。

我們首先向 ItemTemplate 新增一個刪除按鈕。

當單擊 CommandName 屬性為“Edit” 、 “Update” 或 “Cancel” 的按鈕時,將觸發 DataList 的 ItemCommand 事件和一個額外的事件(比如,當使用 “Edit” 時,將觸發 EditCommand 事件)。 與此類似,CommandName 屬性設定為“Delete” 的 DataList 中的任何 Button 、LinkButton 或 ImageButton 都會觸發 DeleteCommand 事件(同時觸發 ItemCommand)。

向ItemTemplate 中編輯按鈕的旁邊新增一個刪除按鈕,將其CommandName 屬性設定為“Delete” 。新增該按鈕控制元件後,DataList 的 ItemTemplate 宣告式語法應該類似如下:

  1. <ItemTemplate>
  2.     <h5>
  3.         <asp:Label runat="server" ID="ProductNameLabel"
  4.             Text='<%# Eval("ProductName") %>' />
  5.     </h5>
  6.     Price: <asp:Label runat="server" ID="Label1"
  7.             Text='<%# Eval("UnitPrice", "{0:C}") %>' />
  8.     <br />
  9.     <asp:Button runat="server" id="EditProduct" CommandName="Edit"
  10.         Text="Edit" />
  11.     <asp:Button runat="server" id="DeleteProduct" CommandName="Delete"
  12.         Text="Delete" />
  13.     <br />
  14.     <br />
  15. </ItemTemplate>

接下來,使用以下程式碼為 DataList 的DeleteCommand 事件建立Event Handler 。

  1. protected void DataList1_DeleteCommand(object source, DataListCommandEventArgs e)
  2. {
  3.     // Read in the ProductID from the DataKeys collection
  4.     int productID = Convert.ToInt32(DataList1.DataKeys[e.Item.ItemIndex]);
  5.     // Delete the data
  6.     ProductsBLL productsAPI = new ProductsBLL();
  7.     productsAPI.DeleteProduct(productID);
  8.     // Rebind the data to the DataList
  9.     DataList1.DataBind();
  10. }

單擊刪除按鈕引發一個回傳,並且激發 DataList 的 DeleteCommand 事件。在 Event Handler 中,從 DataKeys 集合訪問被單擊產品的 ProductID 值。接下來,呼叫 ProductsBLL 類的 DeleteProduct 方法,將產品刪除。

在將產品刪除後,將資料與 DataList 再次繫結(DataList1.DataBind()) 十分重要,否則 DataList 將會繼續顯示已刪除的產品。

小結

雖然 DataList 沒有 GridView 所具備的單擊編輯與刪除功能,但是隻需要很少的程式碼就可以增強 DataList ,將這些功能包括在內。在本篇教程中,我們瞭解瞭如何建立一個兩列的產品列表,從表中可以刪除產品並對其名稱和價格進行編輯。新增編輯和刪除功能用到了ItemTemplate 和 EditItemTemplate 中的相應 Web 控制元件;是一個建立相應 Event Handler的過程;是一個讀取使用者輸入數值以及主鍵值的過程;是一個與業務邏輯層進行連線的過程。

雖然我們已經將基本的編輯與刪除功能新增至了DataList ,但是 DataList 缺乏更加高階的特性。比如,沒有輸入欄位確認—— 如果使用者輸入了“價格太高”,當試圖將其轉換為十進位制形式時, Decimal.Parse 就會出現異常。同樣,如果在業務邏輯層或資料訪問層出現資料更新問題,在使用者面前就會出現標準的錯誤螢幕。而在刪除按鈕中沒有任何形式的確認,也會出現將產品意外刪除的情況。

在以後的教程中,我們將就如何提高編輯使用者的體驗進行討論。

快樂程式設計!