探讨与插入、更新、删除相关的事件17

简介

当使用 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 会传递 null 值到 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 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 ,表示更新产品信息的请求失败。否则,它会相应地更新已有产品记录的 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 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 enumeration ,能够正确解析货币符号、逗号、小数点等任何情况中的小数。

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

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

步骤2 :禁止NULL UnitPrice

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

被传入GridView 的 RowUpdating Event Handler 的GridViewUpdateEventArgs 对象,含有一个Cancel 属性,如果设为 true ,就会终止更新过程。我们来扩展 RowUpdating 的 Event Handler ,如果 NewValues 集合中的 UnitPrice 值为 null ,程序就要将 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 void Page_Load(object sender, EventArgs e) 

    MustProvideUnitPriceMessage.Visible = false; 
}

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

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; 
    } 
}

如果用户试图不指定价格就存储产品,就会取消更新,并显示帮助消息。虽然数据库(以及业务逻辑)允许 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) 的名称与价格。然而,我们需要的是一个插入界面,通过这个界面能使用户快速将新产品添加到数据库。

图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 void ObjectDataSource1_Inserting 
    (object sender, ObjectDataSourceMethodEventArgs e) 

 
}

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

protected void ObjectDataSource1_Inserting 
    (object sender, ObjectDataSourceMethodEventArgs e) 

    e.InputParameters["CategoryID"] = 1; 
    e.InputParameters["SupplierID"] = 1; 
}

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

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

小结

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

快乐编程!

posted @ 2016-05-01 21:27  迅捷之风  阅读(119)  评论(0编辑  收藏  举报