本文档是 Visual Basic 教程 (切换到 Visual C# 教程)

当对 ASP.NET Web 数据控件进行插入、更新、删除的操作前、操作过程中以及操作后,会发生一些事件。在本教程中,我们将详细介绍这些事件的使用。我们还将了解如何定制编辑界面来只更新产品字段的子集。

« 前一篇教程  |  下一篇教程 »

简介

当使用 GridView、DetailsView、FormView 控件内置的插入、编辑、删除功能时,在最终用户添加新记录、 或更新、删除已有记录的过程中,会发生多个步骤。我们在前一篇教程中讨论过,当在 GridView 中 编辑一行时,Edit 按钮会被 Update 与 Cancel 按钮代替,BoundField 会变为 TextBox。当最终用户更新数据 并单击 Update 后,回传时会执行以下步骤:

  1. GridView 使用所编辑记录的唯一标识字段(通过 DataKeyNames 属性)以及用户输入值为 ObjectDataSource 的 UpdateParameters 赋值。
  2. GridView 调用其 ObjectDataSource 的 Update() 方法,这进而又会调用底层对象中适当的方法(在我们之前的教程中,调用的是 ProductsDAL.UpdateProduct)
  3. 底层数据现在包括了更新过的变化,被重新绑定到 GridView

在这一系列的步骤中,触发了多个事件,这就使我们能够创建 Event Handler,在需要的地方加入自定义 的逻辑。例如,在步骤 1 之前,会触发 GridView 的 RowUpdating 事件。在这时,如果有校验错误,我们 就可以取消这个更新请求。当调用 Update() 方法时,会触发 ObjectDataSource 的 Updating 事件,这就为增 加或自定义任何 UpdateParameters 的值提供了机会。当 ObjectDataSource 底层对象的方法执行完毕之后,会 触发 ObjectDataSource 的 Updated 事件。Updated 事件的 Event Handler 可以对更新操作的细节进行检查,例如 多少行受到了影响,以及是否发生了异常。最后,在步骤 2 之后,会触发 GridView 的 RowUpdated 事件; 这个事件的 Event Handler 可以对刚执行的更新操作的附加信息进行检查。

图 1 描述了这一系列的事件,以及更新 GridView 时的步骤。图 1 中的事件模式并不只局限于 GridView 的 更新。 从 GridView、DetailsView、FormView 中插入、更新、删除数据时,对 Web 数据控件与 ObjectDataSource 都会触发同样顺序的 Pre 级与 Post 级事件。

图1: 当在 GridView 中更新数据时,触发一系列的 Pre 级与 Post 级事件

在本教程中,我们将介绍怎样使用这些事件来扩展 ASP.NET Web 数据控件的内置插入、更新、删除功能。 我们还将了解如何定制编辑界面来只更新产品字段的子集。

步骤 1:更新产品的 ProductName 与 UnitPrice 字段

前面的教程讲到,所有非只读的产品字段都必须包括在编辑界面中。如果我们要从 GridView 中删除一个 字段 — 比如 QuantityPerUnit — 当更新数据时,Web 数据控件不会为 ObjectDataSource 的 QuantityPerUnit UpdateParameters 赋值。然后,ObjectDataSource 会传递空值到 UpdateProduct Business Logic Layer (BLL) 方法中,这会将被编辑的 QuantityPerUnit 列变为 NULL 值。与之类似,如果从编辑界面中删除一个必需的字段(例如 ProductName),那么更新将会失败,产生一个“Column 'ProductName' does not allow nulls”异常。上述行为的原因是,ObjectDataSource 配置为调用 ProductsBLL 类的 UpdateProduct 方法,这个方法期待每个产品字段都有一个输入参数。因此,对于这个方法的每个输入参数,ObjectDataSource 的 UpdateParameters 集合都包含了一个对应的参数。

如果我们想提供一个 Web 数据控件,它允许最终用户仅更新字段的一个子集,那么我们需要通过编程为 ObjectDataSource 的 Updating Event Handler 中缺少的 UpdateParameters 值赋值;或者创建并调用一个只期待字段子集的 BLL 方法。我们来探讨后一个方法。

具体而言,我们要创建一个页面,它在一个可编辑的 GridView 中只显示ProductName 与 UnitPrice 字段。GridView 的编辑界面将只允许用户更新这两个显示的字段,ProductName 与 UnitPrice。因为该编辑界面仅提供了产品字段的一个子集,所以我们需要创建一个 ObjectDataSource,它使用已有 BLL 的 UpdateProduct 方法,并在它的 Updating Event Handler 中通过编程为缺少的产品字段赋值;或者创建一个新的 BLL 方法,这个方法仅接受 GridView 中定义字段的子集。对于本教程来说,我们选用后者,创建 UpdateProduct 方法的一个重载,这个重载版本仅有三个输入参数:productName、unitPrice、productID:

<System.ComponentModel.DataObjectMethodAttribute _
    (System.ComponentModel.DataObjectMethodType.Update, False)> _
    Public Function UpdateProduct(productName As String, _
        unitPrice As Nullable(Of Decimal), productID As Integer) _
        As Boolean
    Dim products As Northwind.ProductsDataTable = _
        Adapter.GetProductByProductID(productID)
    If products.Count = 0 Then
        Return False
    End If
    Dim product As Northwind.ProductsRow = products(0)
    product.ProductName = productName
    If Not unitPrice.HasValue Then
        product.SetUnitPriceNull()
    Else
        product.UnitPrice = unitPrice.Value
    End If
    Dim rowsAffected As Integer = Adapter.Update(product)
    Return rowsAffected = 1
End Function

与原来的 UpdateProduct 方法一样,这个重载方法首先检查在数据库中是否存在指定 ProductID 的产品。如果不存在,它会返回 False,表示更新产品信息的请求失败。否则,它会相应地更新已有产品记录的 ProductName 和 UnitPrice 字段,并调用 TableAdpater 的Update() 方法,传入 ProductsRow 实例,执行更新。

ProductsBLL 类有了这个附加的方法之后,我们就可以创建简化的 GridView 界面了。打开 EditInsertDelete 文件夹中的 DataModificationEvents.aspx,将一个 GridView 加到页面。创建一个新的 ObjectDataSource,将它配置为使用 ProductsBLL 类,这个类的 Select() 方法映射为 GetProducts,Update() 方法映射为重载的 UpdateProduct,而重载方法的输入参数只有 productName、unitPrice 和 productID。图 2 显示了使用 Create Data Source 向导,将 ObjectDataSource 的 Update() 方法映射为 ProductsBLL 类的新重载方法 UpdateProduct。

图2: 将 ObjectDataSource 的 Update() 方法映射为新的重载方法 UpdateProduct

因为示例的开始阶段只需要编辑数据的功能,而不需要插入或删除记录,所以我们要花点时间来明确指出 ObjectDataSource 的 Insert() 与 Delete() 方法不应该映射为 ProductsBLL 类的任何方法,操作方法是进入 INSERT 与 DELETE 选项卡,从下拉列表中选择 (None)。

图3: 在 INSERT 与 DELETE 选项卡,从下拉列表中选择 (None)

完成本向导后,从 GridView 的智能标记中,选中 Enable Editing 复选框。

当完成 Create Data Source 向导,并将其绑定到 GridView 之后,Visual Studio就创建好了两个控件的声明式语法。进入 Source 视图,检查 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() 方法没有映射,所以不存在InsertParameters 或 DeleteParameters 部分。 此外,因为 Update() 方法被映射为 UpdateProduct 重载方法,这个重载方法只接受三个输入参数,所以 UpdateParameters 部分只有三个 Parameter 实例。

注意,ObjectDataSource 的 OldValuesParameterFormatString 属性被设为了 original_{0}。当使用 Configure Data Source 向导时,这个属性是 Visual Studio 自动设置的。然而,因为 BLL 方法并不期待输入原来的 ProductID 值,所以要从 ObjectDataSource 的声明式语法中完全删除此属性赋值。

注意:如果您只是简单地从 Design 视图中的 Properties 窗口中清除了OldValuesParameterFormatString 属性值,那么这个属性还是会存在于声明式语法中,只是会被设置为空字符串。您需要从声明式语法中完全删除此属性,或者在 Properties 窗口中,将值设置为默认值,{0}。

虽然 ObjectDataSource 只有产品名称、价格、ID 的 UpdateParameters,Visual Studio 在 GridView 中还是为产品的每个字段加入了 BoundField 或 CheckBoxField。

图4: GridView 对产品的每个字段都包含了一个 BoundField 或 CheckBoxField

当最终用户编辑产品,并单击 Update 按钮时,GridView 会列举那些非只读的字段。然后,将用户输入的 值,为 ObjectDataSource 的 UpdateParameters 集合中的相应参数赋值。如果没有相应的参数,GridView 会向集 合中添加一个。因此,如果我们的 GridView 对产品的所有字段都包含 BoundField 与 CheckBoxField,那么 ObjectDataSource 最终就会调用需要全部这些输入参数的 UpdateProduct 重载,而不管 ObjectDataSource 的声明 式标记仅指定了三个输入参数(见图5)。与之类似,如果 GridView 中有非只读产品字段的某种组合, 这个组合无法和 UpdateProduct 重载的输入参数形成对应,那么当试图更新时将引发异常。

图5: GridView 会向 ObjectDataSource 的 UpdateParameters 集合添加参数

为了确保 ObjectDataSource 调用的是仅带有产品名称、价格、ID 的UpdateProduct 重载,我们需要将 GridView 限 制为只对 ProductName 与 UnitPrice 有可编辑字段。实现办法是删除其他的 BoundField 与 CheckBoxField,或将其 他字段的 ReadOnly 属性设为 True,或者是两者的某种组合。本教程中,我们只删除 GridView 中除了 ProductName 和 UnitPrice BoundField 之外的所有字段,删除之后 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 的视图状态设为 enabled(默认行为)至关重要。如果将 GridView 的 EnableViewState 属性设置为 false,则可能使多个用户无意中同时删除或编辑记录。有关更多信息,请参见警告:在使用支持编辑和/或删除功能并禁用了查看状态的 ASP.NET 2.0 GridViews/DetailsView/FormViews 时的并发问题

改进 UnitPrice 的格式

虽然图 6 中的 GridView 能正常工作,但是 UnitPrice 字段完全没有格式,结果是显示的价格缺少任何货币符号,并且有四位小数。要对不可编辑的行应用货币格式,将 UnitPrice BoundField 的 DataFormatString 属性设为 {0:c},将其 HtmlEncode 属性设为 False 即可。

图7: 对 UnitPrice 的 DataFormatString 与 HtmlEncode 属性进行相应设置

完成此变更后,不可编辑行的价格变成了货币格式;然而,可编辑行仍然显示没有货币符号的值,并且还是四位小数。

图8: 不可编辑行的格式现在变为了货币值

在 DataFormatString 属性中指定的格式化指令可以应用于编辑界面,方法是将BoundField 的 ApplyFormatInEditMode 属性设置为 True(默认是 False)。花点时间将此属性设置为 True。

图9: 将 UnitPrice BoundField 的 ApplyFormatInEditMode 属性设置为 True

完成此变更后,编辑行中显示的 UnitPrice 值也变为了货币格式。

图10: 被编辑行的 UnitPrice 值现在也变为了货币格式

然而,如果使用文本框中的带有货币符号的值来更新产品 — 例如 $19.00 — 则会抛出 FormatException 异常。当 GridView 试图用用户提供的值为 ObjectDataSource 的 UpdateParameters 集合赋值时,它无法将 UnitPrice 字符串“$19.00”转换为参数需要的小数(见图11)。为了修正这个缺陷,我们可以为 GridView 的 RowUpdating 事件创建一个 Event Handler,这个程序能将用户提供的 UnitPrice 当作货币格式的小数进行解析。

GridView 的 RowUpdating 事件第二个参数能接受类型为GridViewUpdateEventArgs的对象,它包括的属性之一是 NewValues 字典,这个字典保存了用户提供的值, 使用该值为 ObjectDataSource 的 UpdateParameters 集合赋值。在 RowUpdating Event Handler 中,我们可以使用下 面的几行代码,将货币格式解析为小数值,然后用解析出的小数值覆盖 NewValues 集合中已有的 UnitPrice 值:

Protected Sub GridView1_RowUpdating(sender As Object, e As GridViewUpdateEventArgs) _
    Handles GridView1.RowUpdating
    If e.NewValues("UnitPrice") IsNot Nothing Then
        e.NewValues("UnitPrice") = _
            Decimal.Parse(e.NewValues("UnitPrice").ToString(), _
                System.Globalization.NumberStyles.Currency)
    End If
End Sub

如果用户提供了一个 UnitPrice 值(例如“$19.00”),那么将使用 Decimal.Parse进行计算,将这个货币值解析为小数值,然后用小数值覆盖货币值。这个方法利用System.Globalization命名空间中的 NumberStyles enumeration,能够正确解析货币符号、逗号、小数点等任何情况中的小数。

图 11 既显示了当用户提供的 UnitPrice 为货币符号时所出现的问题,也显示了如何利用 GridView 的 RowUpdating Event Handler 来正确解析这种输入。

图11: 被编辑行的 UnitPrice 值现在也变为了货币格式

步骤 2:禁止UnitPrice被赋NULL值

虽然数据库的配置是允许 Products 表格的 UnitPrice 列中有 NULL 值,但是我们可能想阻止访问这个页面的 用户给UnitPrice指定一个Null值。换句话说,如果用户在编辑产品行时没有输入 UnitPrice 值,那么我们就不 要将结果存储到数据库,取而代之的是显示一条消息,通过这条消息告诉用户,必须为任何被编辑的产 品指定一个价格。

被传入 GridView 的 RowUpdating Event Handler的GridViewUpdateEventArgs 对象,含有一个 Cancel 属性,如果设为 True,就会终止更新过程。我们来扩展 RowUpdating 的 Event Handler,如果 NewValues 集合中的 UnitPrice 值为 空,程序就要将 e.Cancel 设为 True,并显示消息解释原因。

首先,在页面上添加一个名为 MustProvideUnitPriceMessage 的 Web Label 控件。当对产品进行更新时,如果用 户没有指定 UnitPrice 值,则将这个 Label 控件。将 Label 的 Text 属性设为“You must provide a price for the product.” 我还在 Styles.css 中创建好了一个新的 CSS 类,名字是 Warning,定义如下:

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

最后,将 Label 的 CssClass 属性设为 Warning。此时,Designer 应该在 GridView 上方显示警告信息, 字体为红色,粗体,斜体,特大字号,如图12所示。

图12: 在 GridView 上方已经添加了一个标签

默认情况下,这个 Label 应该是隐藏的,所以要在 Page_Load Event Handler 中将它的 Visible 属性设为 False:

Protected Sub Page_Load(sender As Object, e As System.EventArgs) Handles Me.Load
    MustProvideUnitPriceMessage.Visible = False
End Sub

如果用户试图不指定 UnitPrice 就更新产品,那么要取消更新,显示警告标签。 将 GridView 的 RowUpdating Event Handler 扩充为如下所示:

Protected Sub GridView1_RowUpdating(sender As Object, e As GridViewUpdateEventArgs) _
    Handles GridView1.RowUpdating
    If e.NewValues("UnitPrice") IsNot Nothing Then
        e.NewValues("UnitPrice") = _
            Decimal.Parse(e.NewValues("UnitPrice").ToString(), _
                System.Globalization.NumberStyles.Currency)
    Else
        MustProvideUnitPriceMessage.Visible = True
        e.Cancel = True
    End If
End Sub

如果用户试图不指定价格就存储产品,就会取消更新,并显示帮助消息。虽然数据库(以及业务逻辑) 允许 NULL 的 UnitPrice,我们这个特定的 ASP.NET 页面却不允许这种情况。

图13:用户不能将 UnitPrice 设为空白

到目前为止,我们已经看到了怎样利用 GridView 的 RowUpdating 事件来通过编程改变参数值,再为 ObjectDataSource 的 UpdateParameters 集合赋值,我们还看到了如何完全取消更新过程。这些概念对 DetailsView 和 FormView 控件同样适用,也适用于插入和删除。

这些任务也可以在 ObjectDataSource 级别完成,方法是使用它的 Inserting、Updating、Deleting 事件的 Event Handler。 这些事件在调用底层对象的相关方法之前触发,它们提供了最后的机会来对输入参数集合进行修改,或者 完全取消操作。这三个事件的 Event Handler 被传入了类型为 ObjectDataSourceMethodEventArgs的对象,我们要关注其两个属性:

  • Cancel,如果将其设为 True,会取消正在执行的操作
  • InputParameters,它是 InsertParameters、UpdateParameters、DeleteParameters 的集合,取决于 Event Handler 处理的是 Inserting、 Updating 还是 Deleting 事件

为了举例说明怎样在 ObjectDataSource 级别使用参数值,我们在页面中加入一个DetailsView,它会允许用户添 加一个新产品。这个 DetailsView 用于提供一个界面,使用这个界面能将一个新产品快速添加到数据库。 为了保持用户界面一致,当添加新产品时,我们允许用户仅输入 ProductName 与UnitPrice 字段值。默认情况 下,DetailsView 的插入界面中没有提供的值将在数据库中被设为 NULL 值。然而,我们可以利用 ObjectDataSource 的 Inserting 事件,来写入不同的默认值,我们下面将会看到这点。

步骤 3:提供添加新产品的界面

从 Toolbox 中,拖动 DetailsView 到 GridView 上方的设计器上,清除 Height 与 Width 属性,并将其绑定到页面上已经存在的 ObjectDataSource 上。这会为产品的每个字段添加一个 BoundField 或 CheckBoxField。因为我们要使用这个 DetailsView 来添加新产品,所以我们需要选中智能标记中的Enable Inserting 选项;然而,并没有这个选项,原因是 ObjectDataSource 的 Insert() 方法并没有映射为 ProductsBLL 类中的方法(回想一下,我们在配置数据源时将它映射为 (None) — 见图3)。

为了配置 ObjectDataSource,请您从它的智能标记中选择 Configure Data Source 链接,启动向导。第一个屏幕中可以更改 ObjectDataSource 绑定到的底层对象;保留它的 ProductsBLL 设置。下一个屏幕列出了从 ObjectDataSource 的方法到底层对象方法的映射。虽然我们明确指明了 Insert() 与 Delete() 方法不应该映射为任何方法,如果您进入 INSERT 与 DELETE 选项卡,您会看到那里存在一个映射。这是因为 ProductsBLL 的 AddProduct 与 DeleteProduct 方法使用了 DataObjectMethodAttribute 属性,指出它们分别是 Insert() 与 Delete() 的默认方法。因此,当您每次运行向导时,ObjectDataSource 向导都会选择它们,除非明确指定了其他值。

保留 Insert() 方法指向 AddProduct 方法不变,然而还是要将 DELETE 选项卡的下拉列表设为 (None)。

图14: 将 INSERT 选项卡的下拉列表设为 AddProduct 方法

图15: 将 DELETE 选项卡的下拉列表设为 (None)

进行这些变更之后,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 的智能标记现在会包含 Enable Inserting 复选框;回到设计器并选中此选项。接下来,减少 DetailsView,使其仅具有两个 BoundField(ProductName 与 UnitPrice)以及 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) 的名称与价格。然而,我们需要的是一个插入界面,通过这个界面能使用户快速将新产品添加到数据库。

Figure 16: DetailsView 现在呈现为只读模式

为了将 DetailsView 显示为插入模式,我们需要将 DefaultMode 属性设为 Inserting。这将令 DetailsView 在首次访问时呈现为插入模式,在插入一个新记录后,也会保持插入模式。如图 17 所示,这个 DetailsView 提供了添加新记录的快速界面。

图17: DetailsView 提供了快速添加新产品的界面

当用户输入产品名称与价格(例如图17中的“Acme Water”与 1.99),并单击Insert 时,会发生回传, 并启动插入的工作流程,最终生成一条新的产品记录,添加到数据库。DetailsView 会保留它的插入界面, 为了包含新产品,GridView 会自动重新绑定到它的数据源,如图 18 所示。

图18: 产品“Acme Water”已经添加到数据库

图18中的 GridView 并没有显示出来,DetailsView 界面中缺少的产品字段 — CategoryID、SupplierID、QuantityPerUnit 等等 — 在数据库中都被赋值为 NULL。您可以执行下列步骤看到这点:

  1. 转到 Visual Studio 中的 Server Explorer(服务器资源管理器)。
  2. 展开 NORTHWND.MDF 数据库节点
  3. 右键单击 Products 数据库表格节点
  4. 选择 Show Table Data

这将列出 Products 表中的所有记录。如图 19 所示,除了 ProductID、ProductName、UnitPrice,我们新产品的所有其他列值都是 NULL。

图19: DetailsView 中没有提供的产品字段都被赋值为 NULL

我们可能想为这些列中的一个或更多提供非 NULL 的默认值,原因可能是 NULL 并不是默认值的最好选择,也可能是数据库的列本身并不允许 NULL。为了达到这个目的,我们可以通过编程对 DetailsView 的 InputParameters 集合赋值。这个赋值操作可以在 DetailsView 的 ItemInserting 事件的 Event Handler 中实现,也可以在 ObjectDataSource 的 Inserting 事件中实现。因为我们之前已经研究过了在 Web 数据控件级别使用 pre 级与 post 级事件,所以这次我们来探讨怎样使用 ObjectDataSource 的事件。

步骤 4:为 CategoryID 与 SupplierID 参数赋值

对于本教程,我们假定在我们的应用程序中,当通过这个界面添加一个新产品时,CategoryID 与 SupplierID 应该被赋值为 1。前面提到,ObjectDataSource 有一对 pre 级与 post 级事件,在修改数据的过程中会触发它们。当触发它的 Insert() 方法时,ObjectDataSource 首先会产生它的 Inserting 事件,然后会调用 Insert() 方法映射到的另一方法,最后产生 Inserted 事件。Inserting Event Handler 提供给了我们最后的机会来改变输入参数或完全取消操作。

注意:在实际的应用程序中,您可能需要让用户指定类别与供应商,或者根据某种准则或业务逻辑来选取此值(而不是盲目地选择 1 作为 ID 值)。虽然这样,但本例的目的只是举例说明怎样通过编程对 ObjectDataSource 的 pre 级事件中的输入参数赋值。

花点时间,为 ObjectDataSource 的 Inserting 事件创建一个 Event Handler。注意,这个 Event Handler 的第二个输入参数是类型为ObjectDataSourceMethodEventArgs 的对象,它有一个属性能访问参数集合(InputParameters),还有一个属性能取消操作(Cancel)。

Protected Sub ObjectDataSource1_Inserting _
    (sender As Object, e As ObjectDataSourceMethodEventArgs) _
    Handles ObjectDataSource1.Inserting
End Sub

此时,InputParameters 属性包含了 ObjectDataSource 的 InsertParameters 集合,集合的值来自 DetailsView。 要更改这些参数的值,您只需使用:e.InputParameters["paramName"] = value。因此,要将 CategoryID 与 SupplierID 的值设为 1,可以将 Inserting Event Handler 修改为如下所示:

Protected Sub ObjectDataSource1_Inserting _
    (sender As Object, e As ObjectDataSourceMethodEventArgs) _
    Handles ObjectDataSource1.Inserting
    e.InputParameters("CategoryID") = 1
    e.InputParameters("SupplierID") = 1
End Sub

这次,当添加一个新产品(例如 Acme Soda)时,新产品的 CategoryID 与SupplierID 列被设为了 1(见图20)。

图20: 现在,新产品的 CategoryID 与 SupplierID 值被设为了1

小结

在编辑、插入、删除的过程中,Web 数据控件与 ObjectDataSource 都经历了多个 pre 级与 post 级事件。在本教程中,我们研究了 pre 级事件,看到了怎样利用这些事件来自定义输入参数或完全取消修改数据的操作。我们对 Web 数据控件与 ObjectDataSource 的事件都进行了研究。在下一篇教程中,我们将研究怎样为 post 级事件创建并应用 Event Handler。

快乐编程!





下一篇教程