插入、更新和刪除資料的概觀 (C#)

作者:Scott Mitchell

下載 PDF

在本教學課程中,我們將瞭解如何將 ObjectDataSource 的 Insert () 、Update () 和 Delete () 方法對應至 BLL 類別的方法,以及如何設定 GridView、DetailsView 和 FormView 控件以提供數據修改功能。

簡介

在過去數個教學課程中,我們已瞭解如何使用 GridView、DetailsView 和 FormView 控件,在 ASP.NET 頁面中顯示數據。 這些控制件只會處理提供給它們的數據。 通常,這些控件會透過使用數據源控件來存取數據,例如 ObjectDataSource。 我們已瞭解 ObjectDataSource 如何作為 ASP.NET 頁面與基礎數據之間的 Proxy。 當 GridView 需要顯示資料時,它會叫用其 ObjectDataSource Select() 的 方法,然後從我們的商業規則層 (BLL) 叫用方法,它會在適當的數據存取層 (DAL) TableAdapter 中呼叫方法,進而將查詢傳送 SELECT 至 Northwind 資料庫。

回想一下,當我們在第 一個教學課程中於 DAL 中建立 TableAdapters 時,Visual Studio 會自動新增從基礎資料庫數據表插入、更新和刪除數據的方法。 此外,在 建立商業規則層 中,我們會在 BLL 中設計方法,以向下呼叫這些數據修改 DAL 方法。

除了其 Select() 方法之外,ObjectDataSource 也有 Insert()Update()Delete() 方法。 Select()如同方法,這三種方法可以對應至基礎物件中的方法。 當設定為插入、更新或刪除數據時,GridView、DetailsView 和 FormView 控制項會提供使用者介面來修改基礎數據。 此使用者介面會 Insert()呼叫 ObjectDataSource 的、 Update()Delete() 方法,然後叫用基礎對象的相關聯方法 (請參閱圖 1) 。

ObjectDataSource 的 Insert () 、Update () 和 Delete () 方法可作為 BLL 中的 Proxy

圖 1:ObjectDataSource 的 Insert()Update()Delete() 方法可作為 BLL 中的 Proxy (按兩下即可檢視大小完整的影像)

在本教學課程中,我們將瞭解如何將 ObjectDataSource 的 Insert()Update()Delete() 方法對應至 BLL 中類別的方法,以及如何設定 GridView、DetailsView 和 FormView 控件,以提供數據修改功能。

步驟 1:建立插入、更新和刪除教學課程網頁

在開始探索如何插入、更新和刪除數據之前,讓我們先花一點時間在網站專案中建立 ASP.NET 頁面,我們將需要本教學課程和接下來的幾個頁面。 首先,新增名為 EditInsertDelete的新資料夾。 接下來,將下列 ASP.NET 頁面新增至該資料夾,請務必將每個頁面與 Site.master 主版頁面產生關聯:

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

新增數據 Modification-Related 教學課程的 ASP.NET 頁

圖 2:新增數據 Modification-Related 教學課程的 ASP.NET 頁面

就像在其他資料夾中一樣, Default.aspx 資料夾中 EditInsertDelete 會列出其區段中的教學課程。 回想一下, SectionLevelTutorialListing.ascx 使用者控件會提供這項功能。 因此,請將此使用者控制件Default.aspx從 方案總管 拖曳至頁面的設計檢視,以將它新增至 。

將 SectionLevelTutorialListing.ascx 使用者控件新增至 Default.aspx

圖 3:將使用者控件新增 SectionLevelTutorialListing.ascxDefault.aspx (按兩下即可檢視大小完整的影像)

最後,將頁面新增為檔案的專案 Web.sitemap 。 具體來說,請在自定義格式 <siteMapNode>之後新增下列標記:

<siteMapNode title="Editing, Inserting, and Deleting"
    url="~/EditInsertDelete/Default.aspx"
    description="Samples of Reports that Provide Editing, Inserting,
                  and Deleting Capabilities">
    <siteMapNode url="~/EditInsertDelete/Basics.aspx"
        title="Basics"
        description="Examines the basics of data modification with the
                      GridView, DetailsView, and FormView controls." />
    <siteMapNode url="~/EditInsertDelete/DataModificationEvents.aspx"
        title="Data Modification Events"
        description="Explores the events raised by the ObjectDataSource
                      pertinent to data modification." />
    <siteMapNode url="~/EditInsertDelete/ErrorHandling.aspx"
        title="Error Handling"
        description="Learn how to gracefully handle exceptions raised
                      during the data modification workflow." />
    <siteMapNode url="~/EditInsertDelete/UIValidation.aspx"
        title="Adding Data Entry Validation"
        description="Help prevent data entry errors by providing validation." />
    <siteMapNode url="~/EditInsertDelete/CustomizedUI.aspx"
        title="Customize the User Interface"
        description="Customize the editing and inserting user interfaces." />
    <siteMapNode url="~/EditInsertDelete/OptimisticConcurrency.aspx"
        title="Optimistic Concurrency"
        description="Learn how to help prevent simultaneous users from
                      overwritting one another s changes." />
    <siteMapNode url="~/EditInsertDelete/ConfirmationOnDelete.aspx"
        title="Confirm On Delete"
        description="Prompt a user for confirmation when deleting a record." />
    <siteMapNode url="~/EditInsertDelete/UserLevelAccess.aspx"
        title="Limit Capabilities Based on User"
        description="Learn how to limit the data modification functionality
                      based on the user role or permissions." />
</siteMapNode>

更新 Web.sitemap之後,請花點時間透過瀏覽器檢視教學課程網站。 左側功能表現在包含編輯、插入和刪除教學課程的專案。

網站地圖現在包含編輯、插入和刪除教學課程的專案

圖 4:網站地圖現在包含編輯、插入和刪除教學課程的專案

步驟 2:新增和設定 ObjectDataSource 控件

由於 GridView、DetailsView 和 FormView 各自有不同的數據修改功能和配置,因此讓我們個別檢查每一個。 不過,讓我們只建立一個可共用三個控件範例的單一 ObjectDataSource,而不是使用它自己的 ObjectDataSource。

Basics.aspx開啟頁面,將 ObjectDataSource 從 [工具箱] 拖曳至 Designer,然後按兩下其智慧標記中的 [設定數據源] 連結。 ProductsBLL由於是唯一提供編輯、插入和刪除方法的 BLL 類別,因此請將 ObjectDataSource 設定為使用此類別。

將 ObjectDataSource 設定為使用 ProductsBLL 類別

圖 5:將 ObjectDataSource 設定為使用 ProductsBLL 類別 (按兩下以檢視完整大小的映像)

在下一個畫面中,我們可以指定類別的方法 ProductsBLL 對應至 ObjectDataSource 的 Select()Insert()Update()Delete() ,方法是選取適當的索引標籤,然後從下拉式清單中選擇 方法。 圖 6 現在看起來應該很熟悉,會將 ObjectDataSource Select() 的 方法對應至 ProductsBLL 類別 GetProducts() 的 方法。 Insert()從頂端清單中選取適當的索引標籤,即可設定、 Update()Delete() 方法。

讓 ObjectDataSource 傳回所有產品

圖 6:讓 ObjectDataSource 傳回所有產品 (按兩下即可檢視大小完整的影像)

圖 7、8 和 9 會顯示 ObjectDataSource 的 UPDATE、INSERT 和 DELETE 索引卷標。 設定這些索引標籤,讓 Insert()Update()Delete() 方法分別叫 ProductsBLL 用 類別的 UpdateProductAddProductDeleteProduct 方法。

將 ObjectDataSource 的 Update () 方法對應至 ProductBLL 類別的 UpdateProduct 方法

圖 7:將 ObjectDataSource Update() 的 方法對應至 ProductBLL 類別 UpdateProduct 的方法 (按兩下即可檢視大小完整的影像)

將 ObjectDataSource 的 Insert () 方法對應至 ProductBLL 類別的 AddProduct 方法

圖 8:將 ObjectDataSource Insert() 的 方法對應至 ProductBLL 類別的 Add Product 方法 (按兩下即可檢視大小完整的影像)

將 ObjectDataSource 的 Delete () 方法對應至 ProductBLL 類別的 DeleteProduct 方法

圖 9:將 ObjectDataSource Delete() 的 方法對應至 ProductBLL 類別 DeleteProduct 的方法, (按兩下即可檢視大小完整的影像)

您可能已注意到 UPDATE、INSERT 和 DELETE 索引標籤中的下拉式清單已選取這些方法。 這是因為我們使用 DataObjectMethodAttribute 裝飾 方法的 ProductsBLL。 例如,DeleteProduct 方法具有下列簽章:

[System.ComponentModel.DataObjectMethodAttribute
    (System.ComponentModel.DataObjectMethodType.Delete, true)]
public bool DeleteProduct(int productID)
{
    ...
}

屬性 DataObjectMethodAttribute 會指出每個方法的用途,無論是選取、插入、更新或刪除,以及是否為預設值。 如果您在建立 BLL 類別時省略這些屬性,則必須從 UPDATE、INSERT 和 DELETE 索引標籤標手動選取方法。

確定適當的 ProductsBLL 方法對應至 ObjectDataSource 的 Insert()Update()Delete() 方法之後,按兩下 [完成] 以完成精靈。

檢查 ObjectDataSource 的標記

透過其精靈設定 ObjectDataSource 之後,請移至 [來源] 檢視,以檢查產生的宣告式標記。 標記 <asp:ObjectDataSource> 會指定要叫用的基礎物件和方法。 此外,還有 DeleteParametersInsertParametersUpdateParameters和 對應至 類別AddProductUpdateProductDeleteProduct 方法的輸入參數ProductsBLL

<asp:ObjectDataSource ID="ObjectDataSource1" runat="server"
    DeleteMethod="DeleteProduct" InsertMethod="AddProduct"
    OldValuesParameterFormatString="original_{0}" SelectMethod="GetProducts"
    TypeName="ProductsBLL" UpdateMethod="UpdateProduct">
    <DeleteParameters>
        <asp:Parameter Name="productID" Type="Int32" />
    </DeleteParameters>
    <UpdateParameters>
        <asp:Parameter Name="productName" Type="String" />
        <asp:Parameter Name="supplierID" Type="Int32" />
        <asp:Parameter Name="categoryID" Type="Int32" />
        <asp:Parameter Name="quantityPerUnit" Type="String" />
        <asp:Parameter Name="unitPrice" Type="Decimal" />
        <asp:Parameter Name="unitsInStock" Type="Int16" />
        <asp:Parameter Name="unitsOnOrder" Type="Int16" />
        <asp:Parameter Name="reorderLevel" Type="Int16" />
        <asp:Parameter Name="discontinued" Type="Boolean" />
        <asp:Parameter Name="productID" Type="Int32" />
    </UpdateParameters>
    <InsertParameters>
        <asp:Parameter Name="productName" Type="String" />
        <asp:Parameter Name="supplierID" Type="Int32" />
        <asp:Parameter Name="categoryID" Type="Int32" />
        <asp:Parameter Name="quantityPerUnit" Type="String" />
        <asp:Parameter Name="unitPrice" Type="Decimal" />
        <asp:Parameter Name="unitsInStock" Type="Int16" />
        <asp:Parameter Name="unitsOnOrder" Type="Int16" />
        <asp:Parameter Name="reorderLevel" Type="Int16" />
        <asp:Parameter Name="discontinued" Type="Boolean" />
    </InsertParameters>
</asp:ObjectDataSource>

ObjectDataSource 包含其相關聯方法之每個輸入參數的參數,就像當 ObjectDataSource 設定為呼叫需要輸入參數 (的 select 方法時,就會出現 s 的清單 SelectParameter ,例如 GetProductsByCategoryID(categoryID)) 。 如我們稍後所見,這些 DeleteParametersUpdateParametersInsertParameters 的值會在叫用 ObjectDataSource 的 Insert()Update()Delete() 方法之前,由 GridView、DetailsView 和 FormView 自動設定。 這些值也可以視需要以程式設計方式設定,因為我們將在未來的教學課程中討論。

使用精靈設定為 ObjectDataSource 的其中一個副作用是,Visual Studio 會將 OldValuesParameterFormatString 屬性 設定為 original_{0}。 這個屬性值是用來包含正在編輯之數據的原始值,而且在兩個案例中很有用:

  • 如果在編輯記錄時,用戶可以變更主鍵值。 在此情況下,必須提供新的主鍵值和原始主鍵值,以便找到具有原始主鍵值的記錄,並據以更新其值。
  • 使用開放式並行存取時。 開放式並行存取是一種技術,可確保兩個同時使用者不會覆寫彼此的變更,而且是未來教學課程的主題。

屬性 OldValuesParameterFormatString 會指出基礎物件更新和刪除原始值方法中輸入參數的名稱。 當我們探索開放式並行存取時,我們將更詳細地討論此屬性及其用途。 不過,我現在會啟動它,因為我們的 BLL 方法不預期原始值,因此請務必移除這個屬性。 OldValuesParameterFormatString如果數據 Web 控件嘗試叫用 ObjectDataSource 的 或 Delete() 方法,因為 ObjectDataSource Update() 會嘗試傳入 UpdateParametersDeleteParameters 指定的 和原始值參數,所以將 屬性設定為預設) ({0} 以外的任何專案,會導致錯誤。

如果這一點並不清楚,請不要擔心,我們將在未來的教學課程中檢查此屬性及其公用程式。 目前,請務必從宣告式語法完全移除此屬性宣告,或將值設定為預設值 ({0}) 。

注意

如果您只是OldValuesParameterFormatString清除 [設計] 檢視中 屬性視窗 的屬性值,屬性仍會存在於宣告式語法中,但設定為空字串。 不幸的是,這仍然會導致上述相同的問題。 因此,請完全從宣告式語法中移除 屬性,或從 屬性視窗 將值設定為預設值 {0}

步驟 3:新增數據 Web 控制項並設定數據以進行數據修改

將 ObjectDataSource 新增至頁面並設定之後,我們就可以將數據 Web 控件新增至頁面以顯示數據,並提供方法供終端使用者修改。 我們將分別查看 GridView、DetailsView 和 FormView,因為這些數據 Web 控件在其數據修改功能和設定中有所不同。

如本文其餘部分所示,透過 GridView、DetailsView 和 FormView 控件新增非常基本的編輯、插入和刪除支援,就像檢查幾個複選框一樣簡單。 真實世界中有許多細微和邊緣案例,讓提供這類功能比點和點選更相關。 不過,本教學課程僅著重於證明簡化的數據修改功能。 未來的教學課程將檢查在真實世界設定中可能會發生的疑慮。

從 GridView 刪除數據

首先,將 GridView 從 [工具箱] 拖曳至 Designer。 接下來,從 GridView 智慧標記的下拉式清單中選取 ObjectDataSource 至 GridView。 此時 GridView 的宣告式標記將會是:

<asp:GridView ID="GridView1" runat="server" AutoGenerateColumns="False"
    DataKeyNames="ProductID" DataSourceID="ObjectDataSource1">
    <Columns>
        <asp:BoundField DataField="ProductID" HeaderText="ProductID"
            InsertVisible="False"
            ReadOnly="True" SortExpression="ProductID" />
        <asp:BoundField DataField="ProductName" HeaderText="ProductName"
            SortExpression="ProductName" />
        <asp:BoundField DataField="SupplierID" HeaderText="SupplierID"
           SortExpression="SupplierID" />
        <asp:BoundField DataField="CategoryID" HeaderText="CategoryID"
           SortExpression="CategoryID" />
        <asp:BoundField DataField="QuantityPerUnit"
           HeaderText="QuantityPerUnit"
           SortExpression="QuantityPerUnit" />
        <asp:BoundField DataField="UnitPrice" HeaderText="UnitPrice"
           SortExpression="UnitPrice" />
        <asp:BoundField DataField="UnitsInStock"
           HeaderText="UnitsInStock" SortExpression="UnitsInStock" />
        <asp:BoundField DataField="UnitsOnOrder"
           HeaderText="UnitsOnOrder" SortExpression="UnitsOnOrder" />
        <asp:BoundField DataField="ReorderLevel"
           HeaderText="ReorderLevel" SortExpression="ReorderLevel" />
        <asp:CheckBoxField DataField="Discontinued"
           HeaderText="Discontinued" SortExpression="Discontinued" />
        <asp:BoundField DataField="CategoryName"
           HeaderText="CategoryName" ReadOnly="True"
            SortExpression="CategoryName" />
        <asp:BoundField DataField="SupplierName"
            HeaderText="SupplierName" ReadOnly="True"
            SortExpression="SupplierName" />
    </Columns>
</asp:GridView>

透過其智慧標記將 GridView 系結至 ObjectDataSource 有兩個優點:

  • BoundFields 和 CheckBoxFields 會自動針對 ObjectDataSource 所傳回的每個字段建立。 此外,BoundField 和 CheckBoxField 的屬性會根據基礎欄位的元數據來設定。 例如, ProductIDCategoryNameSupplierName 欄位在 中 ProductsDataTable 標示為唯讀,因此在編輯時不應更新。 為了容納這一點,這些 BoundFields 的 ReadOnly 屬性 會設定為 true
  • DataKeyNames 屬性會指派給基礎物件的主鍵字段 () 。 使用 GridView 來編輯或刪除資料時,這是不可或缺的,因為此屬性表示欄位 (或字段集,) 唯一識別每個記錄。 如需屬性的詳細資訊DataKeyNames,請參閱使用可選取的主網格線檢視搭配詳細數據詳細數據檢視教學課程的 Master/Detail。

雖然 GridView 可以透過 屬性視窗 或宣告式語法系結至 ObjectDataSource,但這麼做需要您手動新增適當的 BoundField 和DataKeyNames標記。

GridView 控制項提供資料列層級編輯和刪除的內建支援。 設定 GridView 以支援刪除新增 [刪除] 按鈕的數據行。 當使用者按下特定資料列的 [刪除] 按鈕時,回傳就會發生,而 GridView 會執行下列步驟:

  1. 指派 ObjectDataSource DeleteParameters 的值 ()
  2. 叫用 ObjectDataSource 的 Delete() 方法,刪除指定的記錄
  3. GridView 會叫用其 Select() 方法,將其本身重新系結至 ObjectDataSource

指派給 DeleteParameters 的值是按下 [刪除] 按鈕的數據列 (字段) 的值 DataKeyNames 。 因此,必須正確設定 GridView 的屬性 DataKeyNames 。 如果遺失, DeleteParameters 則會在步驟 1 中指派 null 值,這會導致步驟 2 中的任何已刪除記錄。

注意

集合 DataKeys 會儲存在 GridView 的控制狀態中,這表示 DataKeys 即使 GridView 的檢視狀態已停用,也會在回傳中記住這些值。 不過,對於支援編輯或刪除的 GridViews 而言,檢視狀態仍然相當重要, (默認行為) 。 如果您將 GridView 的 EnableViewState 屬性設定為 false,編輯和刪除行為將適用於單一使用者,但如果有並行使用者刪除數據,則這些並行使用者可能會意外刪除或編輯他們不想要的記錄。

這個相同的警告也適用於 DetailsViews 和 FormViews。

若要將刪除功能新增至 GridView,只需移至其智慧標記並核取 [啟用刪除] 複選框即可。

核取 [啟用刪除] 複選框

圖 10:核取 [啟用刪除] 複選框

核取智慧標記中的 [啟用刪除] 複選框會將 CommandField 新增至 GridView。 CommandField 會在 GridView 中轉譯數據行,其中包含執行下列一或多項工作的按鈕:選取記錄、編輯記錄,以及刪除記錄。 我們先前看到 CommandField 的運作方式是使用 可選取的主方格檢視與詳細數據詳細數據檢視教學課程來選取 Master/DetailView 中的記錄。

CommandField 包含數 ShowXButton 個屬性,指出 CommandField 中顯示的按鈕系列。 核取 [啟用刪除] 複選框,將屬性true新增至 GridView 的 Columns 集合中的 CommandFieldShowDeleteButton

<asp:GridView ID="GridView1" runat="server" AutoGenerateColumns="False"
    DataKeyNames="ProductID" DataSourceID="ObjectDataSource1">
    <Columns>
        <asp:CommandField ShowDeleteButton="True" />
        ... BoundFields removed for brevity ...
    </Columns>
</asp:GridView>

此時,我們相信,我們已完成將刪除支援新增至 GridView! 如圖 11 所示,透過瀏覽器瀏覽此頁面時,會出現 [刪除] 按鈕的數據行。

CommandField 新增刪除按鈕的數據行

圖 11:CommandField 會新增 [刪除按鈕] 欄, (按兩下即可檢視大小完整的影像)

如果您已經從頭開始建置本教學課程,在測試此頁面時,按兩下 [刪除] 按鈕將會引發例外狀況。 繼續閱讀以了解引發這些例外狀況的原因,以及如何修正這些例外狀況。

注意

如果您遵循本教學課程隨附的下載,這些問題已經考慮過。 不過,我們鼓勵您閱讀下列詳細數據,以協助找出可能發生的問題和適當的因應措施。

如果嘗試刪除產品時,您會收到一個例外狀況,其訊息類似於 “ObjectDataSource 'ObjectDataSource1' 找不到具有參數的非泛型方法 'DeleteProduct':p roductID,original_ProductID”,您可能會忘記從 ObjectDataSource 移除 OldValuesParameterFormatString 屬性。 指定 屬性時 OldValuesParameterFormatString ,ObjectDataSource 會嘗試傳入 productIDoriginal_ProductID 輸入參數至 DeleteProduct 方法。 DeleteProduct不過,只接受單一輸入參數,因此例外狀況。 拿掉 OldValuesParameterFormatString 屬性 (或將它設定為 {0}) 會指示 ObjectDataSource 不要嘗試傳入原始輸入參數。

確定 OldValuesParameterFormatString 屬性已清除

圖 12:確定 OldValuesParameterFormatString 屬性已清除 (按一下即可檢視完整大小的影像)

即使您已移除 OldValuesParameterFormatString 屬性,在嘗試刪除含有訊息的產品時仍會收到例外狀況:「DELETE 語句與 REFERENCE 條件約束 『FK_Order_Details_Products』 衝突」。Northwind 資料庫包含 和 Products 數據表之間的Order Details外鍵條件約束,這表示如果數據表中有Order Details一或多筆記錄,就無法從系統刪除產品。 由於 Northwind 資料庫中的每個產品在 中 Order Details至少有一筆記錄,因此必須先刪除產品的相關訂單詳細數據記錄,才能刪除任何產品。

外鍵條件約束禁止刪除產品

圖 13:外鍵條件約束禁止刪除產品 (按兩下即可檢視完整大小的影像)

在我們的教學課程中,讓我們只刪除數據表中的所有記錄 Order Details 。 在真實世界中,我們需要:

  • 讓另一個畫面管理訂單詳細數據資訊
  • DeleteProduct擴增 方法以包含邏輯以刪除指定的產品訂單詳細數據
  • 修改 TableAdapter 所使用的 SQL 查詢,以包含刪除指定的產品訂單詳細數據

讓我們只刪除數據表中的所有記錄 Order Details ,以規避外鍵條件約束。 移至 Visual Studio 中的 [伺服器總管],以滑鼠右鍵按鍵按兩下 NORTHWND.MDF 節點,然後選擇 [追加查詢]。 然後,在查詢視窗中執行下列 SQL 語句: DELETE FROM [Order Details]

從訂單詳細數據數據表中刪除所有記錄

圖 14:從 Order Details 資料表刪除所有記錄 (按鍵即可檢視完整大小的影像)

清除 Order Details 資料表之後,按兩下 [刪除] 按鈕將會刪除產品,而不會發生錯誤。 如果按下 [刪除] 按鈕並不會刪除產品,請檢查以確定 GridView 的 DataKeyNames 屬性設定為主鍵字段, (ProductID) 。

注意

按兩下 [刪除] 按鈕時,回傳就會發生,並刪除記錄。 這很危險,因為很容易不小心按兩下錯誤資料列的 [刪除] 按鈕。 在未來的教學課程中,我們將瞭解如何在刪除記錄時新增客戶端確認。

使用 GridView 編輯數據

除了刪除之外,GridView 控件也提供內建的數據列層級編輯支援。 設定 GridView 以支援編輯新增 [編輯] 按鈕的數據行。 從用戶的觀點來看,按兩下資料列的 [編輯] 按鈕會導致該數據列變成可編輯,並將儲存格轉換成包含現有值的文字框,並以 [更新] 和 [取消] 按鈕取代 [編輯] 按鈕。 進行所需的變更之後,終端使用者可以按兩下 [更新] 按鈕來認可變更,或按下 [取消] 按鈕來捨棄變更。 不論是哪一種情況,按兩下 [更新] 或 [取消],GridView 就會回到其預先編輯狀態。

從頁面開發人員的觀點來看,當用戶按下特定數據列的 [編輯] 按鈕時,回傳會接著執行下列步驟:

  1. GridView 的屬性 EditItemIndex 會指派給按兩下 [編輯] 按鈕的數據列索引
  2. GridView 會叫用其 Select() 方法,將其本身重新系結至 ObjectDataSource
  3. 符合 EditItemIndex 的數據列索引會以「編輯模式」轉譯。在此模式中,[編輯] 按鈕會由 [更新] 和 [取消] 按鈕和 BoundFields 取代,其 ReadOnly 屬性為 False (預設) 會轉譯為 TextBox Web 控件,其 Text 屬性會指派給數據欄位的值。

此時,標記會傳回瀏覽器,讓使用者對數據列的數據進行任何變更。 當使用者按兩下 [更新] 按鈕時,就會發生回傳,且 GridView 會執行下列步驟:

  1. ObjectDataSource UpdateParameters 的值 () 會指派終端使用者在 GridView 編輯介面中輸入的值
  2. 叫用 ObjectDataSource 的 Update() 方法,並更新指定的記錄
  3. GridView 會叫用其 Select() 方法,將其本身重新系結至 ObjectDataSource

在步驟 1 中指派給 UpdateParameters 的主鍵值來自 屬性中指定的 DataKeyNames 值,而非主鍵值則來自已編輯數據列之 TextBox Web 控制件中的文字。 與刪除一樣,請務必正確設定 GridView 的屬性 DataKeyNames 。 如果遺失, UpdateParameters 主要索引鍵值將會在步驟 1 中指派一個 null 值,進而不會在步驟 2 中產生任何更新的記錄。

只要核取 GridView 智慧標記中的 [啟用編輯] 複選框,即可啟用編輯功能。

核取 [啟用編輯] 複選框

圖 15:核取 [啟用編輯] 複選框

如有) 需要,核取 [啟用編輯] 複選框將會視需要新增 CommandField (,並將其 ShowEditButton 屬性設定為 true。 如我們稍早所見,CommandField 包含數 ShowXButton 個屬性,指出 CommandField 中顯示的按鈕系列。 核取 [啟用編輯] 複選框會將 ShowEditButton 屬性新增至現有的 CommandField:

<asp:GridView ID="GridView1" runat="server" AutoGenerateColumns="False"
    DataKeyNames="ProductID" DataSourceID="ObjectDataSource1">
    <Columns>
        <asp:CommandField ShowDeleteButton="True"
            ShowEditButton="True" />
        ... BoundFields removed for brevity ...
    </Columns>
</asp:GridView>

這就是新增基本的編輯支援。 如圖 16 所示,編輯介面會讓每個 BoundField ReadOnly 的屬性設定為 false (預設) 轉譯為 TextBox。 這包括 和 等CategoryIDSupplierID欄位,這些欄位是其他數據表的索引鍵。

按兩下 [Chai s 編輯] 按鈕以編輯模式顯示資料列

圖 16:按兩下 Chai s [編輯] 按鈕以編輯模式顯示資料列, (按兩下即可檢視大小完整的影像)

除了要求使用者直接編輯外鍵值之外,編輯介面的介面還缺少下列方式:

  • 如果使用者輸入 CategoryIDSupplierID 不存在於資料庫中,則會 UPDATE 違反外鍵條件約束,導致引發例外狀況。
  • 編輯介面不包含任何驗證。 如果您未提供必要值 (,例如 ProductName) ,或輸入預期數值的字串值, (例如在文本框中輸入 “Too much!” UnitPrice) ,則會擲回例外狀況。 未來的教學課程將探討如何將驗證控件新增至編輯使用者介面。
  • 目前 ,所有 非只讀的產品欄位都必須包含在 GridView 中。 如果我們要從 GridView 移除欄位,例如 UnitPrice,在更新數據時,GridView 不會設定UpdateParametersUnitPrice值,這會將資料庫記錄UnitPrice的變更為NULL值。 同樣地,如果從 GridView 移除所需的欄位 ProductName,更新將會失敗,且上述相同的「數據行 』ProductName' 不允許 Null」例外狀況。
  • 編輯介面格式設定會留下許多需要。 UnitPrice會顯示四個小數點。 在理想情況下, CategoryIDSupplierID 值會包含DropDownLists,列出系統中的類別和供應商。

這些都是我們目前必須使用的缺點,但未來教學課程將會加以解決。

使用 DetailsView 插入、編輯和刪除資料

如先前教學課程中所見,DetailsView 控件會一次顯示一筆記錄,例如 GridView,可讓您編輯和刪除目前顯示的記錄。 終端使用者從 DetailsView 編輯和刪除項目的經驗,以及從 ASP.NET 端的工作流程與 GridView 的工作流程相同。 DetailsView 與 GridView 的差異在於它也會提供內建的插入支援。

若要示範 GridView 的數據修改功能,請先將 DetailsView 新增至 Basics.aspx 現有 GridView 上方的頁面,並透過 DetailsView 的智慧標記將它系結至現有的 ObjectDataSource。 接下來,清除 DetailsView 的 HeightWidth 屬性,然後從智慧標記中檢查 [啟用分頁] 選項。 若要啟用編輯、插入和刪除支援,只要勾選智慧標記中的 [啟用編輯]、[啟用插入] 和 [啟用刪除] 複選框即可。

顯示 [DetailsView 工作] 視窗的螢幕快照,其中已選取 [啟用插入]、[啟用編輯] 和 [啟用刪除] 複選框。

圖 17:設定 DetailsView 以支援編輯、插入和刪除

如同 GridView,新增編輯、插入或刪除支援會將 CommandField 新增至 DetailsView,如下列宣告式語法所示:

<asp:DetailsView ID="DetailsView1" runat="server" AutoGenerateRows="False"
    DataKeyNames="ProductID" DataSourceID="ObjectDataSource1" AllowPaging="True">
    <Fields>
        <asp:BoundField DataField="ProductID"
            HeaderText="ProductID" InsertVisible="False"
            ReadOnly="True" SortExpression="ProductID" />
        <asp:BoundField DataField="ProductName"
            HeaderText="ProductName" SortExpression="ProductName" />
        <asp:BoundField DataField="SupplierID" HeaderText="SupplierID"
            SortExpression="SupplierID" />
        <asp:BoundField DataField="CategoryID" HeaderText="CategoryID"
            SortExpression="CategoryID" />
        <asp:BoundField DataField="QuantityPerUnit"
            HeaderText="QuantityPerUnit"
            SortExpression="QuantityPerUnit" />
        <asp:BoundField DataField="UnitPrice"
            HeaderText="UnitPrice" SortExpression="UnitPrice" />
        <asp:BoundField DataField="UnitsInStock"
            HeaderText="UnitsInStock" SortExpression="UnitsInStock" />
        <asp:BoundField DataField="UnitsOnOrder"
            HeaderText="UnitsOnOrder" SortExpression="UnitsOnOrder" />
        <asp:BoundField DataField="ReorderLevel"
            HeaderText="ReorderLevel" SortExpression="ReorderLevel" />
        <asp:CheckBoxField DataField="Discontinued"
            HeaderText="Discontinued" SortExpression="Discontinued" />
        <asp:BoundField DataField="CategoryName"
            HeaderText="CategoryName" ReadOnly="True"
            SortExpression="CategoryName" />
        <asp:BoundField DataField="SupplierName"
            HeaderText="SupplierName" ReadOnly="True"
            SortExpression="SupplierName" />
        <asp:CommandField ShowDeleteButton="True"
            ShowEditButton="True" ShowInsertButton="True" />
    </Fields>
</asp:DetailsView>

請注意,針對 DetailsView,CommandField 預設會出現在 Columns 集合的結尾。 由於 DetailsView 的欄位會轉譯為數據列,所以 CommandField 會顯示為一個數據列,其中包含 DetailsView 底部的 [插入]、[編輯] 和 [刪除] 按鈕。

DetailsView 的螢幕快照,其中 CommandField 顯示為具有 [插入]、[編輯] 和 [刪除] 按鈕的底部數據列。

圖 18:設定 DetailsView 以支援編輯、插入和刪除 (按兩下即可檢視大小完整的影像)

按兩下 [刪除] 按鈕會啟動與 GridView 相同的事件序列:回傳;後面接著以值填DataKeyNames入其 ObjectDataSource 的 DeleteParameters DetailsView;然後以呼叫其 ObjectDataSource 的 Delete() 方法完成,實際上會從資料庫移除產品。 在 DetailsView 中編輯的運作方式也與 GridView 相同。

若要插入,終端使用者會看到 [新增] 按鈕,按兩下時,會以「插入模式」轉譯DetailsView。使用 [插入模式] 時,[新增] 按鈕會由 [插入] 和 [取消] 按鈕取代,而且只會顯示屬性設定true為 (預設) 的 BoundFieldsInsertVisible。 識別為自動遞增欄位的數據欄位,例如 ProductID,在透過智慧標記將 DetailsView 系結至數據源時,其 InsertVisible 屬性 會設定 false 為 。

透過智慧標記將數據源系結至 DetailsView 時,Visual Studio 只會將 屬性false設為InsertVisible自動遞增字段。 唯讀欄位,例如 CategoryNameSupplierName,將會顯示在「插入模式」使用者介面中,除非其 InsertVisible 屬性明確設定為 false。 請花點時間將這兩個字段 InsertVisible 的屬性設定為 false,無論是透過DetailsView的宣告式語法,或是透過智慧標記中的 [編輯字段] 連結。 圖 19 顯示按兩下[編輯字段] 連結, InsertVisible 將屬性設定為 false

顯示 [字段] 視窗的螢幕快照,其中 InsertVisible 屬性設定為 False。

圖 19:Northwind Traders Now 提供 Acme Tea (按兩下即可檢視全尺寸影像)

設定 InsertVisible 屬性之後,請在瀏覽器中檢視 Basics.aspx 頁面,然後按下 [新增] 按鈕。 圖 20 顯示將新的飲料 Acme Tea 新增至我們的生產線時的詳細數據檢視。

此螢幕快照顯示網頁瀏覽器中Basics.aspx頁面的DetailsView。

圖 20:Northwind Traders Now 提供 Acme Tea (按兩下即可檢視全尺寸影像)

輸入 Acme Tea 的詳細資料並按下 [插入] 按鈕之後,回傳就會加入資料庫數據表中 Products ,並將新的記錄新增至資料庫數據表。 由於此 DetailsView 會依其存在於資料庫數據表中的順序列出產品,因此我們必須分頁至最後一個產品,才能查看新產品。

Acme Tea 的詳細數據

圖 21:Acme Tea (按兩下以檢視完整大小的影像)

注意

DetailsView 的 CurrentMode 屬性 指出顯示的介面,而且可以是下列其中一個值: EditInsertReadOnlyDefaultMode 屬性指出 DetailsView 在編輯或插入完成後所傳回的模式,而且對於顯示永久處於編輯或插入模式的 DetailsView 很有用。

DetailsView 的插入和編輯功能有與 GridView 相同的限制:用戶必須透過文本框輸入現有 CategoryIDSupplierID 值;介面缺少任何驗證邏輯;所有不允許 NULL 值或沒有在資料庫層級指定的預設值的產品欄位都必須包含在插入介面中, 依此類故。

我們將在未來的文章中檢查擴充及增強 GridView 編輯介面的技術,也可以套用至 DetailsView 控件的編輯和插入介面。

使用 FormView 取得更具彈性的數據修改使用者介面

FormView 提供插入、編輯和刪除數據的內建支援,但因為它使用範本而不是欄位,所以沒有任何位置可以新增 BoundFields 或 GridView 和 DetailsView 控件所使用的 CommandField,以提供數據修改介面。 相反地,新增新專案或編輯現有專案以及 [新增]、[編輯]、[刪除]、[插入]、[更新] 和 [取消] 按鈕時,必須手動將 Web 控件新增至適當的範本,以收集使用者輸入的 Web 控件。 幸運的是,Visual Studio 會在透過其智慧標記中的下拉式清單將 FormView 系結至數據源時,自動建立所需的介面。

為了說明這些技術,請先將 FormView 新增至 Basics.aspx 頁面,然後從 FormView 的智慧標記將它系結至已建立的 ObjectDataSource。 這會為 FormView 產生 EditItemTemplateInsertItemTemplateItemTemplate ,其中包含 TextBox Web 控件,以收集 [新增]、[編輯]、[刪除]、[插入]、[更新] 和 [取消] 按鈕的使用者輸入和按鈕 Web 控件。 此外,FormView 的 DataKeyNames 屬性會設定為 ObjectDataSource 所傳回物件的主鍵字段 (ProductID) 。 最後,檢查 FormView 智慧標記中的 [啟用分頁] 選項。

下列顯示 FormView 系結至 ObjectDataSource 之後,FormView 的 ItemTemplate 宣告式標記。 根據預設,每個非布爾值產品欄位都會系結至 Text 標籤 Web 控件的 屬性,而每個布爾值字段 (Discontinued) 系結至 Checked 停用的 CheckBox Web 控件的 屬性。 為了讓 [新增]、[編輯] 和 [刪除] 按鈕在按兩下時觸發特定 FormView 行為,其 CommandName 值必須分別設定為 NewEditDelete

<asp:FormView ID="FormView1" runat="server" DataKeyNames="ProductID"
    DataSourceID="ObjectDataSource1" AllowPaging="True">
    <EditItemTemplate>
        ...
    </EditItemTemplate>
    <InsertItemTemplate>
        ...
    </InsertItemTemplate>
    <ItemTemplate>
        ProductID:
        <asp:Label ID="ProductIDLabel" runat="server"
            Text='<%# Eval("ProductID") %>'></asp:Label><br />
        ProductName:
        <asp:Label ID="ProductNameLabel" runat="server"
            Text='<%# Bind("ProductName") %>'>
        </asp:Label><br />
        SupplierID:
        <asp:Label ID="SupplierIDLabel" runat="server"
            Text='<%# Bind("SupplierID") %>'>
        </asp:Label><br />
        CategoryID:
        <asp:Label ID="CategoryIDLabel" runat="server"
            Text='<%# Bind("CategoryID") %>'>
        </asp:Label><br />
        QuantityPerUnit:
        <asp:Label ID="QuantityPerUnitLabel" runat="server"
            Text='<%# Bind("QuantityPerUnit") %>'>
        </asp:Label><br />
        UnitPrice:
        <asp:Label ID="UnitPriceLabel" runat="server"
            Text='<%# Bind("UnitPrice") %>'></asp:Label><br />
        UnitsInStock:
        <asp:Label ID="UnitsInStockLabel" runat="server"
            Text='<%# Bind("UnitsInStock") %>'>
        </asp:Label><br />
        UnitsOnOrder:
        <asp:Label ID="UnitsOnOrderLabel" runat="server"
            Text='<%# Bind("UnitsOnOrder") %>'>
        </asp:Label><br />
        ReorderLevel:
        <asp:Label ID="ReorderLevelLabel" runat="server"
            Text='<%# Bind("ReorderLevel") %>'>
        </asp:Label><br />
        Discontinued:
        <asp:CheckBox ID="DiscontinuedCheckBox" runat="server"
            Checked='<%# Bind("Discontinued") %>'
            Enabled="false" /><br />
        CategoryName:
        <asp:Label ID="CategoryNameLabel" runat="server"
            Text='<%# Bind("CategoryName") %>'>
        </asp:Label><br />
        SupplierName:
        <asp:Label ID="SupplierNameLabel" runat="server"
            Text='<%# Bind("SupplierName") %>'>
        </asp:Label><br />
        <asp:LinkButton ID="EditButton" runat="server"
            CausesValidation="False" CommandName="Edit"
            Text="Edit">
        </asp:LinkButton>
        <asp:LinkButton ID="DeleteButton" runat="server"
            CausesValidation="False" CommandName="Delete"
            Text="Delete">
        </asp:LinkButton>
        <asp:LinkButton ID="NewButton" runat="server"
            CausesValidation="False" CommandName="New"
            Text="New">
        </asp:LinkButton>
    </ItemTemplate>
</asp:FormView>

圖 22 顯示透過瀏覽器檢視 FormView ItemTemplate 的 。 每個產品欄位都會列出底部的 [新增]、[編輯] 和 [刪除] 按鈕。

Defaut FormView ItemTemplate 清單 每個產品欄位以及新增、編輯和刪除按鈕

圖 22:D efaut FormView ItemTemplate 清單 [每個產品欄位] 以及 [新增]、[編輯] 和 [刪除] 按鈕 (按兩下即可檢視大小完整的影像)

如同 GridView 和 DetailsView,單擊 [刪除] 按鈕或任何 Button、LinkButton 或 ImageButton,其CommandName屬性設定為 Delete 會導致回傳、根據 FormView DataKeyNames 的值填入 ObjectDataSourceDeleteParameters,然後叫用 ObjectDataSource 的 Delete() 方法。

當單擊 [編輯] 按鈕后,回傳時,數據會重新系結至 EditItemTemplate,負責轉譯編輯介面。 此介面包含用於編輯數據的 Web 控制項,以及 [更新] 和 [取消] 按鈕。 Visual Studio 產生的預設值 EditItemTemplate 包含任何自動遞增欄位的標籤 () ProductID 、每個非布爾值欄位的 TextBox,以及每個布林值欄位的 CheckBox。 此行為與 GridView 和 DetailsView 控件中自動產生的 BoundFields 非常類似。

注意

FormView 自動產生 EditItemTemplate 的問題之一是,它會針對唯讀字段轉譯 TextBox Web 控件,例如 CategoryNameSupplierName。 我們很快就會瞭解如何考慮這一點。

中的 EditItemTemplate TextBox 控制件會使用雙向數據系結,將其 Text 屬性系結至其對應數據欄位的值。 雙向數據系結由 <%# Bind("dataField") %>表示,會在將數據系結至範本時,以及填入 ObjectDataSource 的參數來插入或編輯記錄時,執行數據系結。 也就是說,當使用者從 按兩下 [ ItemTemplate編輯] 按鈕時, Bind() 此方法會傳回指定的數據域值。 當使用者進行變更並按兩下 [更新] 之後,會套用回對應至所指定 Bind() 資料欄位的值會套用至 ObjectDataSource 的 UpdateParameters。 或者,單向數據系結由 表示 <%# Eval("dataField") %>,只會在將數據系結至範本時擷取數據域值, 而不會 在回傳時將使用者輸入的值傳回至數據源的參數。

下列宣告式標記顯示 FormView 的 EditItemTemplate。 請注意,方法 Bind() 用於此處的數據系結語法中,而且 [更新] 和 [取消] 按鈕 Web 控件會據以設定其 CommandName 屬性。

<asp:FormView ID="FormView1" runat="server" DataKeyNames="ProductID"
    DataSourceID="ObjectDataSource1" AllowPaging="True">
    <EditItemTemplate>
        ProductID:
        <asp:Label ID="ProductIDLabel1" runat="server"
          Text="<%# Eval("ProductID") %>"></asp:Label><br />
        ProductName:
        <asp:TextBox ID="ProductNameTextBox" runat="server"
          Text="<%# Bind("ProductName") %>">
        </asp:TextBox><br />
        SupplierID:
        <asp:TextBox ID="SupplierIDTextBox" runat="server"
          Text="<%# Bind("SupplierID") %>">
        </asp:TextBox><br />
        CategoryID:
        <asp:TextBox ID="CategoryIDTextBox" runat="server"
          Text="<%# Bind("CategoryID") %>">
        </asp:TextBox><br />
        QuantityPerUnit:
        <asp:TextBox ID="QuantityPerUnitTextBox" runat="server"
           Text="<%# Bind("QuantityPerUnit") %>">
        </asp:TextBox><br />
        UnitPrice:
        <asp:TextBox ID="UnitPriceTextBox" runat="server"
           Text="<%# Bind("UnitPrice") %>">
        </asp:TextBox><br />
        UnitsInStock:
        <asp:TextBox ID="UnitsInStockTextBox" runat="server"
           Text="<%# Bind("UnitsInStock") %>">
        </asp:TextBox><br />
        UnitsOnOrder:
        <asp:TextBox ID="UnitsOnOrderTextBox" runat="server"
           Text="<%# Bind("UnitsOnOrder") %>">
        </asp:TextBox><br />
        ReorderLevel:
        <asp:TextBox ID="ReorderLevelTextBox" runat="server"
           Text="<%# Bind("ReorderLevel") %>">
        </asp:TextBox><br />
        Discontinued:
        <asp:CheckBox ID="DiscontinuedCheckBox" runat="server"
            Checked="<%# Bind("Discontinued") %>" /><br />
        CategoryName:
        <asp:TextBox ID="CategoryNameTextBox" runat="server"
             Text="<%# Bind("CategoryName") %>">
        </asp:TextBox><br />
        SupplierName:
        <asp:TextBox ID="SupplierNameTextBox" runat="server"
             Text="<%# Bind("SupplierName") %>">
        </asp:TextBox><br />
        <asp:LinkButton ID="UpdateButton" runat="server"
            CausesValidation="True" CommandName="Update"
            Text="Update">
        </asp:LinkButton>
        <asp:LinkButton ID="UpdateCancelButton" runat="server"
            CausesValidation="False" CommandName="Cancel"
            Text="Cancel">
        </asp:LinkButton>
    </EditItemTemplate>
    <InsertItemTemplate>
        ...
    </InsertItemTemplate>
    <ItemTemplate>
        ...
    </ItemTemplate>
</asp:FormView>

此時,如果我們 EditItemTemplate嘗試使用它,就會擲回例外狀況。 問題在於 和 CategoryNameSupplierName 欄位會轉譯為 中的 EditItemTemplateTextBox Web 控制件。 我們需要將這些 TextBox 變更為 [卷標],或完全移除它們。 讓我們從完全 EditItemTemplate刪除它們。

圖 23 顯示在瀏覽器中按下 [編輯] 按鈕以供 Chai 使用之後的 FormView。 請注意,SupplierName中顯示的 ItemTemplateCategoryName 字段已不存在,因為我們剛從 EditItemTemplate中移除它們。 按兩下 [更新] 按鈕時,FormView 會繼續進行與 GridView 和 DetailsView 控制件相同的步驟順序。

根據預設,EditItemTemplate 會將每個可編輯的產品欄位顯示為 TextBox 或 CheckBox

圖 23:依預設, EditItemTemplate 顯示每個可編輯的產品欄位為 TextBox 或 CheckBox (按兩下即可檢視大小完整的影像)

按兩下 [插入] 按鈕時,FormView 的 ItemTemplate 回傳就會發生。 不過,因為正在新增記錄,所以不會將數據系結至 FormView。 介面 InsertItemTemplate 包含用來新增記錄的 Web 控制件,以及 [插入] 和 [取消] 按鈕。 Visual Studio 所產生的預設值 InsertItemTemplate 包含每個非布爾值欄位的 TextBox,以及每個布林值欄位的 CheckBox,類似於自動產生的 EditItemTemplate介面。 TextBox 控件的 Text 屬性會使用雙向數據系結,系結至其對應數據欄位的值。

下列宣告式標記顯示 FormView 的 InsertItemTemplate。 請注意, Bind() 此方法用於此處的數據系結語法,而且 [插入] 和 [取消] 按鈕 Web 控件會據以設定其 CommandName 屬性。

<asp:FormView ID="FormView1" runat="server" DataKeyNames="ProductID"
    DataSourceID="ObjectDataSource1" AllowPaging="True">
    <EditItemTemplate>
        ...
    </EditItemTemplate>
    <InsertItemTemplate>
        ProductName:
        <asp:TextBox ID="ProductNameTextBox" runat="server"
           Text="<%# Bind("ProductName") %>">
        </asp:TextBox><br />
        SupplierID:
        <asp:TextBox ID="SupplierIDTextBox" runat="server"
           Text="<%# Bind("SupplierID") %>">
        </asp:TextBox><br />
        CategoryID:
        <asp:TextBox ID="CategoryIDTextBox" runat="server"
           Text="<%# Bind("CategoryID") %>">
        </asp:TextBox><br />
        QuantityPerUnit:
        <asp:TextBox ID="QuantityPerUnitTextBox" runat="server"
           Text="<%# Bind("QuantityPerUnit") %>">
        </asp:TextBox><br />
        UnitPrice:
        <asp:TextBox ID="UnitPriceTextBox" runat="server"
           Text="<%# Bind("UnitPrice") %>">
        </asp:TextBox><br />
        UnitsInStock:
        <asp:TextBox ID="UnitsInStockTextBox" runat="server"
           Text="<%# Bind("UnitsInStock") %>">
        </asp:TextBox><br />
        UnitsOnOrder:
        <asp:TextBox ID="UnitsOnOrderTextBox" runat="server"
           Text="<%# Bind("UnitsOnOrder") %>">
        </asp:TextBox><br />
        ReorderLevel:
        <asp:TextBox ID="ReorderLevelTextBox" runat="server"
           Text="<%# Bind("ReorderLevel") %>">
        </asp:TextBox><br />
        Discontinued:
        <asp:CheckBox ID="DiscontinuedCheckBox" runat="server"
           Checked="<%# Bind("Discontinued") %>" /><br />
        CategoryName:
        <asp:TextBox ID="CategoryNameTextBox" runat="server"
            Text="<%# Bind("CategoryName") %>">
        </asp:TextBox><br />
        SupplierName:
        <asp:TextBox ID="SupplierNameTextBox" runat="server"
           Text="<%# Bind("SupplierName") %>">
        </asp:TextBox><br />
        <asp:LinkButton ID="InsertButton" runat="server"
            CausesValidation="True" CommandName="Insert"
            Text="Insert">
        </asp:LinkButton>
        <asp:LinkButton ID="InsertCancelButton" runat="server"
            CausesValidation="False" CommandName="Cancel"
            Text="Cancel">
        </asp:LinkButton>
    </InsertItemTemplate>
    <ItemTemplate>
        ...
    </ItemTemplate>
</asp:FormView>

FormView 的自動產生 InsertItemTemplate有一些細微之處。 具體而言,即使這些欄位是唯讀的,也會建立 TextBox Web 控制件,例如 CategoryNameSupplierNameEditItemTemplate如同 ,我們需要從 InsertItemTemplate移除這些 TextBox。

圖 24 顯示新增產品 Acme Coffee 時,瀏覽器中的 FormView。 請注意,SupplierName中顯示的 ItemTemplateCategoryName 欄位已不存在,因為我們剛移除它們。 按兩下 [插入] 按鈕時,FormView 會繼續進行與DetailsView控件相同的步驟順序,將新記錄新增至 Products 數據表。 圖 25 顯示插入 FormView 后 Acme Coffee 產品的詳細數據。

InsertItemTemplate 會指定 FormView 的插入介面

圖 24InsertItemTemplate 指定 FormView 的插入介面 (按兩下即可檢視完整大小的影像)

New Product、Acme Coffee 的詳細數據會顯示在 FormView 中

圖 25:New Product、Acme Coffee 的詳細數據會顯示在 FormView (Click 以檢視大小完整的影像)

透過將只讀、編輯和插入介面分隔成三個不同的範本,FormView 可讓您更精細地控制這些介面,而不是 DetailsView 和 GridView。

注意

如同 DetailsView,FormView 的 CurrentMode 屬性會指出顯示的介面,而其 DefaultMode 屬性表示 FormView 在編輯或插入完成後傳回的模式。

摘要

在本教學課程中,我們檢查了使用 GridView、DetailsView 和 FormView 插入、編輯和刪除數據的基本概念。 這三個控件都提供一些層級的內建數據修改功能,不需要在 ASP.NET 頁面中撰寫單行程式代碼即可使用,因為數據Web控件和 ObjectDataSource。 不過,簡單點和點選技術會呈現相當簡單的數據修改使用者介面。 若要提供驗證、插入程序設計值、正常處理例外狀況、自定義使用者介面等等,我們必須依賴接下來幾個教學課程將討論的技術。

快樂的程序設計!

關於作者

Scott Mitchell 是 1998 年以來,1998 年與 Microsoft Web 技術合作的 篇 ASP/ASP.NET 書籍和 4GuysFromRolla.com 作者。 Scott 是獨立的顧問、訓練者和作者。 他的最新書籍是 Sams 在 24 小時內自行 ASP.NET 2.0。 您可以透過mitchell@4GuysFromRolla.com部落格連到,也可以透過其部落格來存取,網址為 http://ScottOnWriting.NET