檢查與插入、更新和刪除建立關聯的事件 (C#)

作者 :Scott Mitchell

下載 PDF

在本教學課程中,我們將探討如何使用在 ASP.NET 數據 Web 控件的插入、更新或刪除作業之前、期間和之後發生的事件。 我們也會瞭解如何自定義編輯介面,只更新產品欄位的子集。

簡介

使用 GridView、DetailsView 或 FormView 控件的內建插入、編輯或刪除功能時,當使用者完成新增記錄或刪除現有記錄的程式時,會進行各種步驟。 如 我們在上一個教學課程中所討論,在 GridView 中編輯數據列時,[編輯] 按鈕會由 [更新] 和 [取消] 按鈕取代,而 BoundFields 會變成 TextBoxes。 使用者更新數據並按兩下列步驟:

  1. GridView 會使用DataKeyNames編輯記錄的唯一識別欄位填入其 ObjectDataSource UpdateParameters 的 , (屬性) (,以及使用者輸入的值)
  2. GridView 會叫用其 ObjectDataSource 的 Update() 方法,接著會在上一個教學課程中叫用基礎物件 (ProductsDAL.UpdateProduct的適當方法)
  3. 現在包含更新變更的基礎數據會重新系結至 GridView

在這個步驟序列期間,會引發一些事件,讓我們能夠建立事件處理程序,視需要新增自定義邏輯。 例如,在步驟 1 之前,GridView 的事件 RowUpdating 會引發。 此時,如果發生驗證錯誤,我們可以取消更新要求。 Update()叫用 方法時,ObjectDataSource 的事件Updating會引發,提供新增或自定義任何 UpdateParameters值的機會。 在 ObjectDataSource 的基礎物件方法完成執行之後,就會引發 ObjectDataSource 的事件 Updated 。 事件的事件處理程式 Updated 可以檢查更新作業的詳細數據,例如受影響的數據列數目,以及是否發生例外狀況。 最後,在步驟 2 之後,GridView 的事件 RowUpdated 會引發;此事件的事件處理程式可以檢查剛執行之更新作業的其他資訊。

圖 1 描述更新 GridView 時的這一系列事件和步驟。 圖 1 中的事件模式不是使用 GridView 進行更新的唯一專案。 在 GridView、DetailsView 或 FormView 中插入、更新或刪除數據,會針對數據 Web 控件和 ObjectDataSource,預先和後置事件順序進行預先和後置事件。

更新 GridView 中的數據時引發一系列前置和後置事件

圖 1:更新 GridView 中的數據時引發一系列的前置和後置事件 (按兩下以檢視大小完整的影像)

在本教學課程中,我們將探討如何使用這些事件來擴充內建插入、更新和刪除 ASP.NET 數據 Web 控件的功能。 我們也會瞭解如何自定義編輯介面,只更新產品欄位的子集。

步驟 1:更新產品的ProductNameUnitPrice欄位

在上一個教學課程的編輯介面中 所有不是只讀的產品欄位都必須包含。 如果我們要從 GridView 移除欄位, 例如 QuantityPerUnit - 更新資料時,數據 Web 控制件不會設定 ObjectDataSource QuantityPerUnitUpdateParameters 的值。 ObjectDataSource 接著會將值UpdateProduct傳入 null Business Logic Layer (BLL) 方法,這會將編輯的資料庫記錄數據QuantityPerUnit行變更為NULL值。 同樣地,如果從編輯介面中移除必要的欄位, ProductName更新將會失敗,並顯示「數據行 』ProductName' 不允許 Null」例外狀況。 此行為的原因是 ObjectDataSource 已設定為呼叫 ProductsBLL 類別的 UpdateProduct 方法,這預期每個產品欄位都有輸入參數。 因此,ObjectDataSource 的 UpdateParameters 集合包含每個方法輸入參數的參數。

如果我們想要提供可讓使用者只更新字段子集的數據 Web 控件,則我們需要以程式設計方式設定 ObjectDataSource Updating 事件處理程式中的遺漏UpdateParameters值,或建立並呼叫只預期字段子集的 BLL 方法。 讓我們來探索後者的方法。

具體而言,讓我們建立一個頁面,只 ProductName 顯示可編輯 GridView 中的 和 UnitPrice 字段。 此 GridView 的編輯介面只允許使用者更新兩個顯示的欄位與 ProductNameUnitPrice。 由於此編輯介面只提供產品字段的子集,因此我們需要建立 ObjectDataSource 來使用現有的 BLL UpdateProduct 方法,並在其 Updating 事件處理程式中以程式設計方式設定遺漏的產品域值,或者我們需要建立新的 BLL 方法,預期只有 GridView 中定義的字段子集。 在本教學課程中,讓我們使用後者選項並建立 方法的多 UpdateProduct 載,其中一個只接受三個輸入參數: productNameunitPriceproductID

[System.ComponentModel.DataObjectMethodAttribute
    (System.ComponentModel.DataObjectMethodType.Update, false)]
public bool UpdateProduct(string productName, decimal? unitPrice, int productID)
{
    Northwind.ProductsDataTable products = Adapter.GetProductByProductID(productID);
    if (products.Count == 0)
        // no matching record found, return false
        return false;

    Northwind.ProductsRow product = products[0];

    product.ProductName = productName;
    if (unitPrice == null) product.SetUnitPriceNull();
      else product.UnitPrice = unitPrice.Value;

    // Update the product record
    int rowsAffected = Adapter.Update(product);

    // Return true if precisely one row was updated, otherwise false
    return rowsAffected == 1;
}

如同原始 UpdateProduct 方法,此多載一開始會檢查資料庫中是否有具有指定 ProductID的產品。 如果沒有,則會傳 false回 ,表示更新產品資訊的要求失敗。 否則,它會據以更新現有的產品記錄 ProductNameUnitPrice 字段,並藉由呼叫 TableAdapter 的 Update() 方法來認可更新,並 ProductsRow 傳入 實例。

除了 我們的 ProductsBLL 類別之外,還準備好建立簡化的 GridView 介面。 開啟資料夾中的 EditInsertDeleteDataModificationEvents.aspx並將 GridView 新增至頁面。 建立新的 ObjectDataSource,並將其設定為使用 ProductsBLL 類別與其Select()方法對應,GetProducts以及其Update()方法對應至UpdateProduct只接受 、 unitPriceproductID 輸入參數的多productName載。 圖 2 顯示將 ObjectDataSource Update() 的 方法對應至 ProductsBLL 類別的新 UpdateProduct 方法多載時,建立數據源精靈。

將 ObjectDataSource 的 Update () 方法對應至 New UpdateProduct 多載

圖 2:將 ObjectDataSource 的 Update() 方法對應至 [新增 UpdateProduct 多載] (按兩下即可檢視完整大小的影像)

由於我們的範例一開始只需要編輯數據的能力,但不需要插入或刪除記錄,請花一點時間明確地指出 ObjectDataSource Insert() 的 和 Delete() 方法不應透過移至 INSERT 和 DELETE 索引標籤並選擇 ([無]) 從下拉式清單中對應至任何 ProductsBLL 類別的方法。

從 [插入] 和 [刪除] 索引標籤的 [Drop-Down 列表中選擇 [無) ] (

圖 3:從 [插入] 和 [刪除] 索引標籤的 [Drop-Down 列表中選擇 ([無) ], (按兩下即可檢視大小完整的影像)

完成此精靈之後,請核取 GridView 智慧標記中的 [啟用編輯] 複選框。

完成 [建立數據源精靈] 並系結至 GridView 之後,Visual Studio 已建立這兩個控件的宣告式語法。 移至 [來源] 檢視以檢查 ObjectDataSource 的宣告式標記,如下所示:

<asp:ObjectDataSource ID="ObjectDataSource1" runat="server"
    OldValuesParameterFormatString="original_{0}" SelectMethod="GetProducts"
    TypeName="ProductsBLL" UpdateMethod="UpdateProduct">
    <UpdateParameters>
        <asp:Parameter Name="productName" Type="String" />
        <asp:Parameter Name="unitPrice" Type="Decimal" />
        <asp:Parameter Name="productID" Type="Int32" />
    </UpdateParameters>
</asp:ObjectDataSource>

由於 ObjectDataSource 的 Insert()Delete() 方法沒有對應,因此沒有 InsertParametersDeleteParameters 區段。 此外,由於 Update() 方法會對應至 UpdateProduct 只接受三個輸入參數的方法多載,因此區 UpdateParameters 段只有三 Parameter 個實例。

請注意,ObjectDataSource 的 OldValuesParameterFormatString 屬性設定為 original_{0}。 使用 [設定數據源精靈] 時,Visual Studio 會自動設定此屬性。 不過,由於 BLL 方法不會預期原始 ProductID 值傳入,請從 ObjectDataSource 的宣告式語法完全移除此屬性指派。

注意

如果您只是清除 OldValuesParameterFormatString [設計] 檢視中 屬性視窗 的屬性值,屬性仍會存在於宣告式語法中,但會設定為空字串。 請完全從宣告式語法中移除 屬性,或從 屬性視窗 將值設定為預設值 {0}

雖然 ObjectDataSource 只針對產品名稱、價格和標識碼具有 UpdateParameters ,但 Visual Studio 已在 GridView 中針對每個產品的欄位新增 BoundField 或 CheckBoxField。

GridView 包含每個產品欄位的 BoundField 或 CheckBoxField

圖 4:GridView 包含每個產品欄位的 BoundField 或 CheckBoxField, (按兩下即可檢視完整大小的影像)

當使用者編輯產品並按兩下其 [更新] 按鈕時,GridView 會列舉不是只讀的欄位。 然後,它會將 ObjectDataSource UpdateParameters 集合中對應參數的值設定為使用者輸入的值。 如果沒有對應的參數,GridView 會將一個參數新增至集合。 因此,如果我們的 GridView 包含所有產品欄位的 BoundFields 和 CheckBoxFields,ObjectDataSource 最終會叫 UpdateProduct 用所有參數中的多載,儘管 ObjectDataSource 的宣告標記只指定三個輸入參數 (請參閱圖 5) 。 同樣地,如果 GridView 中有一些未對應至多載輸入參數 UpdateProduct 的非只讀產品欄位群組,則會在嘗試更新時引發例外狀況。

GridView 會將參數新增至 ObjectDataSource 的 UpdateParameters 集合

圖 5:GridView 會將參數新增至 ObjectDataSource 的 UpdateParameters 集合 (按兩下即可檢視大小完整的影像)

為了確保 ObjectDataSource 會叫 UpdateProduct 用只接受產品名稱、價格和標識碼的多載,我們必須將 GridView 限制為只有 ProductNameUnitPrice的可編輯欄位。 這可以藉由移除其他 BoundFields 和 CheckBoxFields、將其他欄位的 ReadOnly 屬性設定為 true或兩者的組合來完成。 在本教學課程中,我們只要移除 和 UnitPrice BoundFields 以外的ProductName所有 GridView 欄位,GridView 的宣告式標記看起來會像這樣:

<asp:GridView ID="GridView1" runat="server" AutoGenerateColumns="False"
    DataKeyNames="ProductID" DataSourceID="ObjectDataSource1">
    <Columns>
        <asp:CommandField ShowEditButton="True" />
        <asp:BoundField DataField="ProductName"
          HeaderText="ProductName" SortExpression="ProductName" />
        <asp:BoundField DataField="UnitPrice" HeaderText="UnitPrice"
          SortExpression="UnitPrice" />
    </Columns>
</asp:GridView>

雖然多 UpdateProduct 載需要三個輸入參數,但我們在 GridView 中只有兩個 BoundField。 這是因為 productID 輸入參數是主鍵值,並透過已編輯數據列的 DataKeyNames 屬性值傳入。

我們的 GridView 以及 UpdateProduct 多載可讓使用者只編輯產品的名稱和價格,而不會遺失任何其他產品字段。

介面允許只編輯產品名稱和價格

圖 6:介面允許僅編輯產品名稱和價格 (按兩下即可檢視完整大小的影像)

注意

如上一個教學課程所述,在預設行為) (啟用 GridView 檢視狀態非常重要。 如果您將 GridView 的 EnableViewState 屬性設定為 false,則會執行不小心刪除或編輯記錄並行用戶的風險。

改善格式設定UnitPrice

雖然圖 6 所示的 GridView 範例運作正常, UnitPrice 但字段完全不會格式化,因此價格顯示缺少任何貨幣符號,而且有四個小數位數。 若要套用不可編輯資料列的貨幣格式設定,只要將 UnitPrice BoundField 的 DataFormatString 屬性設定為 {0:c} ,並將其 HtmlEncode 屬性設定為 false

據以設定 UnitPrice 的 DataFormatString 和 HtmlEncode 屬性

圖 7:設定 UnitPriceDataFormatStringHtmlEncode 屬性[據 (按兩下以檢視完整大小的影像)

透過這項變更,不可編輯的數據列會將價格格式化為貨幣;不過,已編輯的數據列仍然會顯示沒有貨幣符號的值,以及四個小數位數。

不可編輯的數據列現在會格式化為貨幣值

圖 8:不可編輯的數據列現在會格式化為貨幣值, (按兩下即可檢視完整大小的影像)

屬性中指定的 DataFormatString 格式設定指令可以套用至編輯介面,方法是將 BoundField 的 ApplyFormatInEditMode 屬性設定為 true (預設值為 false) 。 請花點時間將這個屬性設定為 true

將 UnitPrice BoundField 的 ApplyFormatInEditMode 屬性設定為 true

圖 9:將 BoundField 的 ApplyFormatInEditMode 屬性設定UnitPricetrue (按兩下即可檢視完整大小的影像)

透過這項變更,編輯數據列中所顯示 的值 UnitPrice 也會格式化為貨幣。

GridView 的螢幕快照,其中顯示已編輯數據列的 UnitPrice 值格式化為貨幣。

圖 10:編輯的數據列 UnitPrice 值現在格式化為貨幣 (按兩下即可檢視大小完整的影像)

不過,在文字框中使用貨幣符號更新產品,例如 $19.00 會擲回 FormatException。 當 GridView 嘗試將使用者提供的值指派給 ObjectDataSource 的UpdateParameters集合時,無法將字串 “$19.00” decimal 轉換成UnitPrice參數所需的 , (請參閱圖 11) 。 若要解決此問題,我們可以為 GridView 的事件RowUpdating建立事件處理程式,並讓它剖析為貨幣格式decimal的使用者UnitPrice

GridView 的事件 RowUpdating 接受其第二個參數 GridViewUpdateEventArgs 類型的物件,其中包含字典做為其其中一個 NewValues 屬性,其中保存可供指派給 ObjectDataSource UpdateParameters 集合的使用者提供值。 我們可以使用貨幣格式與事件處理程式中的下列程式代碼RowUpdating行,以剖析的十進位值覆寫集合中的NewValues現有UnitPrice值:

protected void GridView1_RowUpdating(object sender, GridViewUpdateEventArgs e)
{
  if (e.NewValues["UnitPrice"] != null)
    e.NewValues["UnitPrice"] =
        decimal.Parse(e.NewValues["UnitPrice"].ToString(),
            System.Globalization.NumberStyles.Currency);
}

如果使用者已提供 UnitPrice 值 (,例如 “$19.00”) ,則會以 Decimal.Parse 計算的十進位值覆寫此值,將值剖析為貨幣。 這會正確剖析任何貨幣符號、逗號、小數點等事件中的十進制數,並使用 System.Globalization 命名空間中的 NumberStyles 列舉

圖 11 顯示使用者提供 UnitPrice中貨幣符號所造成的兩個問題,以及 GridView RowUpdating 事件處理程式如何用來正確剖析這類輸入。

此圖顯示 ObjectDataSource 如何處理 UnitPrice 欄位,以及 GridView 的 RowUpdate 事件處理程式如何將字串轉換成小數點。

圖 11:編輯的數據列 UnitPrice 值現在格式化為貨幣 (按兩下即可檢視大小完整的影像)

步驟 2:禁止NULL UnitPrices

當資料庫設定為允許NULL數據表數據UnitPrice行中的Products值時,我們可能會想要防止使用者流覽此特定頁面來指定NULLUnitPrice值。 也就是說,如果使用者在編輯產品數據列時無法輸入 UnitPrice 值,而不是將結果儲存到我們想要顯示訊息給使用者,告知使用者透過此頁面,任何已編輯的產品都必須有指定的價格。

GridViewUpdateEventArgs傳遞至 GridView 事件處理程式的物件RowUpdating包含Cancel屬性,如果設定為 true,則會終止更新程式。 讓我們擴充RowUpdating事件處理程式來設定 truee.Cancel 為 ,並顯示一則訊息,說明集合中的NewValues值是否UnitPricenull

首先,將標籤 Web 控件新增至名為 MustProvideUnitPriceMessage的頁面。 如果使用者在更新產品時無法指定 UnitPrice 值,就會顯示此標籤控件。 將標籤的 Text 屬性設定為「您必須提供產品的價格」。我也會使用下列定義,在 名為 WarningStyles.css建立新的 CSS 類別:

.Warning
{
    color: Red;
    font-style: italic;
    font-weight: bold;
    font-size: x-large;
}

最後,將 Label 的 CssClass 屬性設定為 Warning。 此時,Designer 應該會在 GridView 上方的紅色、粗體、斜體、超大型字型大小中顯示警告訊息,如圖 12 所示。

GridView 上方已新增標籤

圖 12:在 GridView 上方新增標籤 (按一下以檢視大小完整的影像)

根據預設,應該隱藏此標籤,因此請在事件處理程式中將其 Visible 屬性設定為 falsePage_Load

protected void Page_Load(object sender, EventArgs e)
{
    MustProvideUnitPriceMessage.Visible = false;
}

如果用戶嘗試在不指定 UnitPrice的情況下更新產品,我們想要取消更新並顯示警告標籤。 增強 GridView 的 RowUpdating 事件處理程式,如下所示:

protected void GridView1_RowUpdating(object sender, GridViewUpdateEventArgs e)
{
    if (e.NewValues["UnitPrice"] != null)
    {
        e.NewValues["UnitPrice"] =
            decimal.Parse(e.NewValues["UnitPrice"].ToString(),
                System.Globalization.NumberStyles.Currency);
    }
    else
    {
        // Show the Label
        MustProvideUnitPriceMessage.Visible = true;

        // Cancel the update
        e.Cancel = true;
    }
}

如果使用者嘗試儲存產品而不指定價格,則會取消更新,並顯示有用的訊息。 雖然資料庫 (和商業規則) 允許 NULLUnitPrice ,但此特定 ASP.NET 頁面則不允許。

用戶無法將 UnitPrice 保留空白

圖 13:用戶無法保留 UnitPrice 空白 (按兩下即可檢視完整大小的影像)

到目前為止,我們已瞭解如何使用 GridView 的事件 RowUpdating ,以程式設計方式改變指派給 ObjectDataSource 集合的參數 UpdateParameters 值,以及如何完全取消更新程式。 這些概念會繼續至 DetailsView 和 FormView 控件,也適用於插入和刪除。

這些工作也可以透過其 InsertingUpdatingDeleting 事件的事件處理程式,在 ObjectDataSource 層級完成。 這些事件會在叫用基礎對象的相關聯方法之前引發,並提供最後一個機會來修改輸入參數集合,或直接取消作業。 這三個事件的事件處理程式會傳遞 ObjectDataSourceMethodEventArgs 類型的物件,其具有兩個感興趣的屬性:

  • 取消,如果設定為 true,則會取消正在執行的作業
  • InputParameters,這是 、 UpdateParametersDeleteParameters的集合InsertParameters,視事件處理程式是否為InsertingUpdatingDeleting 事件而定

為了說明如何在 ObjectDataSource 層級使用參數值,讓我們在頁面中加入 DetailsView,讓用戶能夠新增產品。 此 DetailsView 將用來提供介面,以便快速將新產品新增至資料庫。 若要在新增產品時保持一致的使用者介面,讓我們允許使用者只輸入 和 UnitPrice 字段的值ProductName。 根據預設,DetailsView 插入介面中未提供的值會設定為 NULL 資料庫值。 不過,我們可以使用 ObjectDataSource 的事件 Inserting 來插入不同的預設值,因為我們很快就會看到。

步驟 3:提供介面以新增產品

將 DetailsView 從 [工具箱] 拖曳至 GridView 上方的 Designer、清除其 HeightWidth 屬性,然後將它系結至頁面上已經存在的 ObjectDataSource。 這會為每個產品的欄位新增 BoundField 或 CheckBoxField。 由於我們想要使用此 DetailsView 來新增產品,因此我們需要從智慧標記中檢查 [啟用插入] 選項;不過,沒有這類選項,因為 ObjectDataSource 的 Insert() 方法並未對應至 類別中的 ProductsBLL 方法, (回想一下,我們在設定數據源時將此對應設定為 (None) 請參閱圖 3) 。

若要設定 ObjectDataSource,請從其智慧標記中選取 [設定數據源] 鏈接,啟動精靈。 第一個畫面可讓您變更 ObjectDataSource 所系結的基礎物件;設定為 ProductsBLL。 下一個畫面會列出從 ObjectDataSource 方法到基礎對象的對應。 即使我們明確指出 Insert()Delete() 方法不應該對應至任何方法,但如果您移至 INSERT 和 DELETE 索引標籤,您會看到對應存在。 這是因為ProductsBLLAddProductDeleteProduct 方法會分別使用 DataObjectMethodAttribute 屬性來指出它們是 和Delete()的預設方法Insert()。 因此,除非您明確指定一些其他值,否則 ObjectDataSource 精靈會在每次執行精靈時選取這些精靈。

Insert()讓方法指向 方法AddProduct,但再次將 DELETE 索引標籤的下拉式清單設定為 ([無]) 。

將 INSERT 索引標籤的 Drop-Down 清單設定為 AddProduct 方法

圖 14:將 INSERT 索引標籤的 [Drop-Down 列表] 設定為 AddProduct [方法] (按兩下即可檢視完整大小的影像)

將 DELETE 索引標籤的 [Drop-Down 清單] 設定為 ([無])

圖 15:將 [刪除] 索引標籤的 [Drop-Down 列表] 設定為 [無] () (按兩下即可檢視大小完整的影像)

進行這些變更之後,ObjectDataSource 的宣告式語法將會展開以包含 InsertParameters 集合,如下所示:

<asp:ObjectDataSource ID="ObjectDataSource1" runat="server"
    SelectMethod="GetProducts" TypeName="ProductsBLL"
    UpdateMethod="UpdateProduct" OnUpdating="ObjectDataSource1_Updating"
    InsertMethod="AddProduct" OldValuesParameterFormatString="original_{0}">
    <UpdateParameters>
        <asp:Parameter Name="productName" Type="String" />
        <asp:Parameter Name="unitPrice" Type="Decimal" />
        <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>

重新執行精靈已新增回 OldValuesParameterFormatString 屬性。 請花點時間將此屬性設定為預設值, () {0} 或完全從宣告式語法中移除此屬性。

透過提供插入功能的 ObjectDataSource,DetailsView 的智慧標記現在會包含 [啟用插入] 複選框;返回 Designer,然後核取此選項。 接下來,剖析 DetailsView,使其只有兩個 BoundFields - ProductNameUnitPrice - 和 CommandField。 此時,DetailsView 的宣告式語法看起來應該像這樣:

<asp:DetailsView ID="DetailsView1" runat="server" AutoGenerateRows="False"
    DataKeyNames="ProductID" DataSourceID="ObjectDataSource1">
    <Fields>
        <asp:BoundField DataField="ProductName"
          HeaderText="ProductName" SortExpression="ProductName" />
        <asp:BoundField DataField="UnitPrice" HeaderText="UnitPrice"
          SortExpression="UnitPrice" />
        <asp:CommandField ShowInsertButton="True" />
    </Fields>
</asp:DetailsView>

圖 16 會在此時透過瀏覽器檢視時顯示此頁面。 如您所見,DetailsView 會列出第一個產品的名稱和價格, (Chai) 。 不過,我們想要的是插入介面,可提供使用者快速將新產品新增至資料庫的方法。

DetailsView 目前以 Read-Only 模式呈現

圖 16:D etailsView 目前以 Read-Only 模式轉譯, (按兩下即可檢視大小完整的影像)

為了在其插入模式中顯示 DetailsView,我們需要將 DefaultMode 屬性設定為 Inserting。 這會在第一次瀏覽時呈現 Insert 模式中的 DetailsView,並在插入新記錄之後將它保留在該處。 如圖 17 所示,這類 DetailsView 提供快速介面來新增記錄。

DetailsView 提供介面來快速新增新產品

圖 17:D etailsView 提供介面,讓您快速新增產品 (按兩下即可檢視大小完整的映像)

當使用者輸入產品名稱和價格 (,例如 「Acme Water」 和 1.99 時,如圖 17) ,然後按兩下 [插入],回傳會接續並開始插入工作流程,並進一步新增至資料庫的新產品記錄。 DetailsView 會維護其插入介面,GridView 會自動重新系結至其數據源,以包含新產品,如圖 18 所示。

產品

圖 18:產品 「Acme Water」 已新增至資料庫

雖然圖 18 中的 GridView 未顯示它,但從 DetailsView 介面 CategoryIDSupplierIDQuantityPerUnit等中缺少的產品欄位會指派 NULL 資料庫值。 您可以執行下列步驟來檢視此問題:

  1. 移至 Visual Studio 中的伺服器總管
  2. 展開 NORTHWND.MDF 資料庫節點
  3. 以滑鼠右鍵按兩下 Products 資料庫數據表節點
  4. 選取 [顯示資料表資料]

這會列出數據表中的所有 Products 記錄。 如圖 19 所示,除了 、 ProductName和 以外的ProductID所有新產品數據行都有NULLUnitPrice值。

DetailsView 中未提供的產品欄位會指派 NULL 值

圖 19:D etailsView 中未提供的產品欄位是 [指派 NULL 的值] (按鍵即可檢視大小完整的影像)

我們可能會想要提供一或多個數據行值以外的 NULL 預設值,可能是因為 NULL 不是最佳預設選項,或是資料庫數據行本身不允許 NULL 。 為了達成此目的,我們可以以程式設計方式設定 DetailsView 集合 InputParameters 的參數值。 您可以在 DetailsView ItemInserting 事件或 ObjectDataSource 事件的 Inserting 事件處理程式中完成此指派。 因為我們已經在數據 Web 控件層級使用前置和後置層級事件,讓我們這次使用 ObjectDataSource 的事件來探索。

步驟 4:將值指派給CategoryIDSupplierID參數

在本教學課程中,讓我們想像透過這個介面新增新產品時,應用程式應該指派 CategoryID 1 的 和 SupplierID 值。 如先前所述,ObjectDataSource 有一對在數據修改程序期間引發的前置和後置事件。 叫用其 Insert() 方法時,ObjectDataSource 會先引發其 Inserting 事件,然後呼叫其 Insert() 方法已對應的方法,最後會引發 Inserted 事件。 Inserting事件處理程式提供最後一個機會來調整輸入參數,或直接取消作業。

注意

在真實世界中,您可能會想要讓使用者指定類別和供應商,或根據某些準則或商業規則來挑選此值 (,而不是盲目選取標識碼 1) 。 不論為何,此範例都會說明如何以程序設計方式從 ObjectDataSource 的預先層級事件設定輸入參數的值。

請花點時間建立 ObjectDataSource Inserting 事件的事件處理程式。 請注意,事件處理程式的第二個輸入參數是 類型的 ObjectDataSourceMethodEventArgs物件,其具有屬性可存取參數集合 () InputParameters ,以及用來取消作業的屬性 Cancel () 。

protected void ObjectDataSource1_Inserting
    (object sender, ObjectDataSourceMethodEventArgs e)
{

}

此時, InputParameters 屬性會包含 ObjectDataSource 的 InsertParameters 集合,其中包含從 DetailsView 指派的值。 若要變更下列其中一個參數的值,只需使用: e.InputParameters["paramName"] = value。 因此,若要將 和 SupplierID 設定CategoryID為1的值,請Inserting調整事件處理程式,如下所示:

protected void ObjectDataSource1_Inserting
    (object sender, ObjectDataSourceMethodEventArgs e)
{
    e.InputParameters["CategoryID"] = 1;
    e.InputParameters["SupplierID"] = 1;
}

這次新增新產品 (例如 Acme Soda) 時, CategoryID 新產品的 和 SupplierID 數據行會設定為 1 (請參閱圖 20) 。

新產品現在已將其 CategoryID 和 SupplierID 值設定為 1

圖 20:新產品現在將其 CategoryIDSupplierID 值設定為 1 (按鍵即可檢視完整大小的影像)

摘要

在編輯、插入和刪除程式期間,數據 Web 控制項和 ObjectDataSource 都會繼續執行一些前置和後置事件。 在本教學課程中,我們檢查了預先層級的事件,並瞭解如何使用這些事件來自定義輸入參數,或從數據 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

特別感謝

本教學課程系列是由許多實用的檢閱者所檢閱。 本教學課程的首席檢閱者是 Jackie Goor 和 Liz Shulok。 想要檢閱即將推出的 MSDN 文章嗎? 如果是,請將一行放在 mitchell@4GuysFromRolla.com。