检查与插入、更新和删除操作有关的事件 (VB)

作者 :斯科特·米切尔

下载 PDF

在本教程中,我们将使用 ASP.NET 数据 Web 控件的插入、更新或删除操作之前、期间和之后发生的事件。 我们还将了解如何自定义编辑界面以仅更新产品字段的子集。

介绍

使用 GridView、DetailsView 或 FormView 控件的内置插入、编辑或删除功能时,最终用户完成添加新记录或更新或删除现有记录的过程时,会执行各种步骤。 如上一教程中所述,在 GridView 中编辑行时,“编辑”按钮将替换为“更新”和“取消”按钮,而 BoundFields 将转换为 TextBoxes。 最终用户更新数据并单击“更新”后,在回发时执行以下步骤:

  1. GridView 使用编辑的记录的唯一标识字段(s)以及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:更新产品的ProductName字段UnitPrice

在上一教程 的编辑界面中, 所有不是只读的产品字段都必须包含。 如果要从 GridView 中删除字段(例如 QuantityPerUnit )更新数据时,Web 控件不会设置 ObjectDataSource QuantityPerUnit UpdateParameters 的值。 然后,ObjectDataSource 将传入业务逻辑层 (BLL) 方法的值NothingUpdateProduct,该方法会将编辑的数据库记录的QuantityPerUnit列更改为值NULL。 同样,如果从编辑界面中删除所需的字段(例如 ProductName),更新将失败,并显示“列'ProductName'不允许 nulls”异常。 此行为的原因是 ObjectDataSource 配置为调用 ProductsBLLUpdateProduct 的方法,该方法需要每个产品字段的输入参数。 因此,ObjectDataSource 的 UpdateParameters 集合包含每个方法输入参数的参数。

如果我们想要提供一个数据 Web 控件,该控件允许最终用户仅更新字段的子集,则需要以编程方式在 ObjectDataSource 的Updating事件处理程序中设置缺失UpdateParameters值,或者创建并调用只需要字段子集的 BLL 方法。 让我们探讨一下后一种方法。

具体而言,让我们创建一个页面,仅显示 ProductName 可编辑 GridView 中的字段和 UnitPrice 字段。 此 GridView 的编辑界面仅允许用户更新两个显示的字段, ProductName 以及 UnitPrice。 由于此编辑接口仅提供产品的字段子集,因此我们要么需要创建使用现有 BLL 方法的 UpdateProduct ObjectDataSource,并在其 Updating 事件处理程序中以编程方式设置缺少的产品字段值,或者我们需要创建一个新的 BLL 方法,该方法只期望 GridView 中定义的字段子集。 在本教程中,让我们使用后一个选项并创建方法的 UpdateProduct 重载,该方法只采用三个输入参数: productNameunitPriceproductID

<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,指示更新产品信息的请求失败。 否则,它会相应地更新现有产品记录和ProductNameUnitPrice字段,并通过调用 TableAdapter Update() 的方法(ProductsRow传入实例)提交更新。

除了类 ProductsBLL 之外,我们已准备好创建简化的 GridView 接口。 打开DataModificationEvents.aspxEditInsertDelete文件夹中,将 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 选项卡并从下拉列表中选择(None)来映射到类的任何ProductsBLL方法。

从“插入”和“删除”选项卡的下拉列表中选择(无)

图 3:从“插入”和“删除”选项卡的下拉列表中选择(无)(单击以查看全尺寸图像

完成此向导后,选中 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()方法没有映射,因此没有或DeleteParameters部分InsertParameters。 此外,由于该方法 Update() 映射到 UpdateProduct 仅接受三个输入参数的方法重载,因此该 UpdateParameters 节只有三 Parameter 个实例。

请注意,ObjectDataSource 的属性 OldValuesParameterFormatString 设置为 original_{0}. 使用“配置数据源”向导时,Visual Studio 会自动设置此属性。 但是,由于 BLL 方法不希望传入原始 ProductID 值,因此请完全从 ObjectDataSource 的声明性语法中删除此属性分配。

注意

如果只是从设计视图中的属性窗口中清除OldValuesParameterFormatString属性值,该属性仍将存在于声明性语法中,但将设置为空字符串。 从声明性语法中删除该属性,或者从属性窗口中将值设置为默认值{0}

虽然 ObjectDataSource 仅具有 UpdateParameters 产品的名称、价格和 ID,但 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仅采用产品名称、价格和 ID 的重载,我们需要将 GridView 限制为仅ProductNameUnitPrice具有可编辑字段。 这可以通过删除其他 BoundFields 和 CheckBoxFields、将其他字段 ReadOnly 的属性 True设置为或两者的某些组合来实现。 在本教程中,我们只需删除除 BoundFields 以外的ProductNameUnitPrice所有 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 中只有两个 BoundFields。 这是因为 productID 输入参数是主键值,通过编辑行的属性值 DataKeyNames 传入。

我们的 GridView 以及 UpdateProduct 重载允许用户仅编辑产品的名称和价格,而不会丢失任何其他产品字段。

该界面仅允许编辑产品名称和价格

图 6:界面仅允许编辑产品名称和价格(单击可查看全尺寸图像

注意

如上一教程中所述,启用 GridView 的视图状态(默认行为)至关重要。 如果将 GridView 属性 EnableViewState 设置为 false,则可能会无意中删除或编辑记录并发用户。

UnitPrice改进格式设置

虽然图 6 中显示的 GridView 示例有效,但 UnitPrice 该字段根本不是格式化的,因此价格显示缺少任何货币符号,并且具有四个小数位数。 若要为不可编辑的行应用货币格式设置,只需将 UnitPrice BoundField 的属性DataFormatString设置为{0:c}HtmlEncode属性。False

相应地设置 UnitPrice 的 DataFormatString 和 HtmlEncode 属性

图 7:相应地设置UnitPrice“和HtmlEncodeDataFormatString”属性“(单击可查看全尺寸图像

通过此更改,不可编辑的行将价格格式化为货币;但是,编辑的行仍然显示没有货币符号的值,并带有四个小数位数。

不可编辑的行现在已格式化为货币值

图 8:不可编辑的行现在已格式化为货币值(单击以查看全尺寸图像

通过将 BoundField ApplyFormatInEditMode 的属性设置为 True (默认值为 False),可以将属性中指定的DataFormatString格式设置说明应用于编辑接口。 花点时间将此属性设置为 True.

将 UnitPrice BoundField 的 ApplyFormatInEditMode 属性设置为 True

图 9:将 UnitPrice BoundField ApplyFormatInEditMode 的属性设置为 True单击可查看全尺寸图像

通过此更改,编辑后的行中显示的值 UnitPrice 也格式化为货币。

GridView 的屏幕截图,其中显示了已编辑行的 UnitPrice 值的格式为货币。

图 10:编辑后的 UnitPrice 行值现在已格式化为货币(单击以查看全尺寸图像

但是,使用 19.00 美元等文本框中的货币符号更新产品会引发一个 FormatException。 当 GridView 尝试将用户提供的值分配给 ObjectDataSource 的 UpdateParameters 集合时,无法将 UnitPrice 字符串“$19.00”转换为 Decimal 参数所需的值(请参阅图 11)。 为了解决此问题,我们可以为 GridView RowUpdating 的事件创建事件处理程序,并将其分析为货币格式Decimal的用户UnitPrice

GridView RowUpdating 的事件接受其第二个参数 GridViewUpdateEventArgs 类型的对象,该对象包含字典NewValues作为其属性之一,用于保存可供分配给 ObjectDataSource 集合UpdateParameters的用户提供的值。 可以使用使用货币格式在事件处理程序中的NewValues以下代码行中用货币格式分析的小数值覆盖集合中的RowUpdating现有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 枚举

图 11 显示了用户提供的 UnitPrice货币符号导致的这两个问题,以及如何使用 GridView 的 RowUpdating 事件处理程序来正确分析此类输入。

显示 ObjectDataSource 如何处理 UnitPrice 字段以及 GridView 的 RowUpdate 事件处理程序如何将字符串转换为十进制的关系图。

图 11:编辑后的 UnitPrice 行值现在已格式化为货币(单击以查看全尺寸图像

步骤 2:禁止NULL UnitPrices

虽然数据库配置为允许NULL表列中的值Products,但我们可能希望阻止访问此特定页面的用户指定NULL UnitPrice UnitPrice值。 也就是说,如果用户在编辑产品行时无法输入 UnitPrice 值,而不是将结果保存到要显示的消息,告知用户,通过此页面,任何编辑的产品都必须指定价格。

GridViewUpdateEventArgs传递到 GridView 事件处理程序的对象RowUpdating包含一个Cancel属性,如果设置为True该属性,则终止更新过程。 让我们扩展RowUpdating事件处理程序以设置为e.CancelTrue并显示一条消息,说明集合中的NewValues值是否UnitPrice具有值Nothing的原因。

首先将标签 Web 控件添加到名为 MustProvideUnitPriceMessage的页面。 如果用户在更新产品时无法指定 UnitPrice 值,将显示此标签控件。 将标签Text的属性设置为“必须提供产品的价格”。我还使用以下定义创建了一个新的 CSS 类Styles.cssWarning

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

最后,将 Label CssClass 的属性设置为 Warning。 此时,设计器应以红色、粗体、斜体、超大型字体大小显示警告消息,如图 12 所示。

已在 GridView 上方添加标签

图 12:在 GridView 上方添加了标签(单击以查看全尺寸图像

默认情况下,此标签应隐藏,因此将其 Visible 属性设置为 False 在事件处理程序中 Page_Load

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

如果用户尝试在不指定 UnitPrice产品的情况下更新产品,我们希望取消更新并显示警告标签。 按如下所示扩充 GridView 的 RowUpdating 事件处理程序:

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

如果用户尝试在不指定价格的情况下保存产品,则会取消更新并显示一条有用的消息。 虽然数据库(和业务逻辑)允许NULLUnitPrice这样做,但此特定 ASP.NET 页则不允许。

用户无法将 UnitPrice 留空

图 13:用户无法留 UnitPrice 空(单击以查看全尺寸图像

到目前为止,我们已了解如何使用 GridView 的事件 RowUpdating 以编程方式更改分配给 ObjectDataSource UpdateParameters 集合的参数值,以及如何完全取消更新过程。 这些概念延续到 DetailsView 和 FormView 控件,还适用于插入和删除。

还可以通过事件处理程序在 ObjectDataSource 级别完成这些任务,以及Deleting事件InsertingUpdating。 这些事件在调用基础对象的关联方法之前触发,并提供修改输入参数集合或彻底取消操作的最后机会。 这三个事件的事件处理程序将传递一个 ObjectDataSourceMethodEventArgs 类型的对象,该对象具有两个感兴趣的属性:

  • 取消,如果设置为 True“取消”,则取消正在执行的操作
  • InputParameters,它是 UpdateParameters/a0> 的InsertParameters集合,或者DeleteParameters,具体取决于事件处理程序是针对InsertingUpdatingDeleting或事件

为了说明如何在 ObjectDataSource 级别使用参数值,让我们在页面中包括一个 DetailsView,允许用户添加新产品。 此 DetailsView 将用于提供一个接口,用于将新产品快速添加到数据库。 若要在添加新产品时保持一致的用户界面,让我们允许用户仅输入字段的值ProductNameUnitPrice。 默认情况下,DetailsView 插入接口中未提供的这些值将设置为 NULL 数据库值。 但是,可以使用 ObjectDataSource Inserting 的事件来注入不同的默认值,正如我们不久将看到的那样。

步骤 3:提供用于添加新产品的接口

将 DetailsView 从工具箱拖到 GridView 上方的设计器上,清除其 Height 属性 Width ,并将其绑定到页面上已存在的 ObjectDataSource。 这将为每个产品的字段添加 BoundField 或 CheckBoxField。 由于我们希望使用此 DetailsView 添加新产品,因此我们需要从智能标记中检查“启用插入”选项;但是,没有这样的选项,因为 ObjectDataSource Insert() 的方法未映射到类中的 ProductsBLL 方法(回想一下,在配置数据源时,我们将此映射设置为“无”),请参阅图 3。

若要配置 ObjectDataSource,请从其智能标记中选择“配置数据源”链接,启动向导。 第一个屏幕允许更改 ObjectDataSource 绑定到的基础对象;将其设置为 ProductsBLL. 下一个屏幕列出了从 ObjectDataSource 方法到基础对象的映射。 尽管我们明确指示 Insert() 不应将和 Delete() 方法映射到任何方法,但如果转到 INSERT 和 DELETE 选项卡,则会看到映射存在。 这是因为ProductsBLL's AddProductDeleteProduct方法使用DataObjectMethodAttribute特性来指示它们是默认方法,并且Delete()分别是默认方法Insert()。 因此,每次运行向导时,ObjectDataSource 向导都会选择这些值,除非显式指定了一些其他值。

Insert()使方法指向AddProduct该方法,但再次将 DELETE 选项卡的下拉列表设置为 (None)。

将 INSERT 选项卡的下拉列表设置为 AddProduct 方法

图 14:将 INSERT 选项卡的下拉列表设置为 AddProduct 方法(单击可查看全尺寸图像

将 DELETE 选项卡的下拉列表设置为 “无”

图 15:将 DELETE 选项卡的下拉列表设置为“无”(单击以查看全尺寸图像

进行这些更改后,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 的智能标记现在将包括“启用插入”复选框;返回设计器并选中此选项。 接下来,分析 DetailsView,使其只有两个 BoundFields 和 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)。 但是,我们想要的是一个插入界面,它为用户快速向数据库添加新产品提供了一种手段。

DetailsView 当前以只读模式呈现

图 16:DetailsView 当前以只读模式呈现(单击以查看全尺寸图像

为了在其插入模式下显示 DetailsView,我们需要将 DefaultMode 属性设置为 Inserting。 当首次访问详细信息视图并在插入新记录后保留该视图时,这将呈现为插入模式。 如图 17 所示,此类 DetailsView 提供了用于添加新记录的快速界面。

DetailsView 提供用于快速添加新产品的接口

图 17:DetailsView 提供用于快速添加新产品的界面(单击以查看全尺寸图像

当用户输入产品名称和价格(如“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 所示,除其他所有新产品列外ProductIDProductName,还UnitPrice具有NULL值。

DetailsView 中未提供的产品字段被分配为 NULL 值

图 19:DetailsView 中未提供的产品字段已 NULL 分配值(单击以查看全尺寸图像

我们可能想要为一个或多个这些列值提供默认值 NULL ,要么 NULL 不是最佳默认选项,要么是因为数据库列本身不允许 NULL 。 为此,我们可以以编程方式设置 DetailsView InputParameters 集合的参数值。 可以在 DetailsView 事件或 ItemInserting ObjectDataSource Inserting 的事件的事件处理程序中完成此分配。 由于我们已在数据 Web 控件级别使用前和后级别事件,因此让我们这次使用 ObjectDataSource 的事件进行探索。

步骤 4:向参数SupplierID分配值CategoryID

在本教程中,我们假设在通过此接口添加新产品时,应用程序应分配一个 CategoryID 值和 SupplierID 值 1。 如前所述,ObjectDataSource 具有一对在数据修改过程中触发的前后级别事件。 调用其 Insert() 方法时,ObjectDataSource 首先引发其 Inserting 事件,然后调用其 Insert() 方法已映射到的方法,最后引发该 Inserted 事件。 Inserting事件处理程序提供了我们最后一个调整输入参数或彻底取消操作的机会。

注意

在实际应用程序中,你可能希望让用户指定类别和供应商,或者根据某些条件或业务逻辑(而不是盲目选择 ID 为 1)为它们选取此值。 不管怎样,该示例都演示如何从 ObjectDataSource 的预级别事件以编程方式设置输入参数的值。

花点时间为 ObjectDataSource Inserting 的事件创建事件处理程序。 请注意,事件处理程序的第二个输入参数是一个类型 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 因此,若要设置 CategoryIDSupplierID 设置为 1 的值,请 Inserting 调整事件处理程序,如下所示:

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)。

新产品现在已将其 CategoryID 和 SupplierID 值设置为 1

图 20:新产品现在已将其 CategoryIDSupplierID 设置为 1(单击可查看全尺寸图像

总结

在编辑、插入和删除过程中,数据 Web 控件和 ObjectDataSource 都继续执行许多预先和后级别事件。 在本教程中,我们检查了预级事件,并了解了如何使用这些事件来自定义输入参数或完全取消数据修改操作,以及数据 Web 控件和 ObjectDataSource 的事件。 在下一教程中,我们将介绍如何为后期事件创建和使用事件处理程序。

快乐编程!

关于作者

斯科特·米切尔,七本 ASP/ASP.NET 书籍的作者和 4GuysFromRolla.com创始人,自1998年以来一直在与Microsoft Web 技术合作。 斯科特担任独立顾问、教练和作家。 他的最新书是 山姆斯在24小时内 ASP.NET 2.0。 他可以通过他的博客联系到mitchell@4GuysFromRolla.com他,可以在该博客中找到http://ScottOnWriting.NET

特别感谢

本教程系列由许多有用的审阅者审阅。 本教程的主要审阅者是 Jackie Goor 和 Liz Shulok。 有兴趣查看即将发布的 MSDN 文章? 如果是这样,请把我扔一条线。mitchell@4GuysFromRolla.com