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

作者 :Scott Mitchell

下载 PDF

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

简介

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

  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 会将 值NothingUpdateProduct传入业务逻辑层 (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 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.aspx打开 文件夹中的 EditInsertDelete ,并将 GridView 添加到页面。 创建一个新的 ObjectDataSource,并将其配置为使用 ProductsBLL 类及其Select()方法映射到 GetProductsUpdate()UpdateProduct 仅接受 、 unitPriceproductID 输入参数的productName重载。 图 2 显示了将 ObjectDataSource 的 Update() 方法映射到 ProductsBLL 类的新 UpdateProduct 方法重载时的“创建数据源”向导。

将 ObjectDataSource 的 Update () 方法映射到新的 UpdateProduct 重载

图 2:将 ObjectDataSource 的 Update() 方法映射到“新建 UpdateProduct 重载 (单击以查看全尺寸图像)

由于我们的示例最初只需要编辑数据的功能,但不需要插入或删除记录,因此请花些时间通过转到“INSERT”和“DELETE”选项卡并从下拉列表中选择“ (None”) ,明确指示不应将 ObjectDataSource 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 针对产品名称、价格和 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 限制为仅 ProductName 具有 和 UnitPrice的可编辑字段。 这可以通过删除其他 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:不可编辑的行现在格式化为货币值 (单击以查看全尺寸图像)

通过将 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集合时,无法将字符串“$19.00”转换为UnitPriceDecimal参数所需的 (请参阅图 11) 。 为了解决此问题,我们可以为 GridView RowUpdating 的事件创建事件处理程序,并使其分析用户提供的 UnitPrice 货币格式 Decimal

GridView 的事件 RowUpdating 接受 GridViewUpdateEventArgs 类型的对象作为其第二个参数,该对象包含一个 NewValues 字典作为其属性之一,该属性保存用户提供的值已准备好分配给 ObjectDataSource 的 UpdateParameters 集合。 我们可以用使用货币格式分析的十进制值覆盖集合中的NewValues现有UnitPrice值,并在事件处理程序中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)
    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表列中UnitPrice的值Products,但我们可能希望阻止访问此特定页面的用户指定NULLUnitPrice值。 也就是说,如果用户在编辑产品行时未能输入 UnitPrice 值,而不是将结果保存到数据库,我们希望显示一条消息,告知用户,通过此页面,任何已编辑的产品都必须指定价格。

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

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

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

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

已在 GridView 上方添加了标签

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

默认情况下,应隐藏此 Label,因此请在事件处理程序中将其Visible属性设置为 FalsePage_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 控件,也适用于插入和删除。

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

  • 取消,如果设置为 True,则取消正在执行的操作
  • InputParameters,它是 、 UpdateParametersDeleteParametersInsertParameters集合,具体取决于事件处理程序是针对 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() 方法映射到任何方法,但如果转到“插入”和“删除”选项卡,你将看到存在映射。 这是因为 ProductsBLLAddProductDeleteProduct 方法使用 DataObjectMethodAttribute 特性来指示它们分别是 和 Delete()的默认方法Insert()。 因此,除非显式指定了其他一些值,否则每次运行向导时,ObjectDataSource 向导都会选择这些值。

Insert() 方法保留为 AddProduct 指向 方法,但再次将“删除”选项卡的下拉列表设置为“无” () 。

将 INSERT 选项卡的 Drop-Down 列表设置为 AddProduct 方法

图 14:将 INSERT 选项卡的 Drop-Down 列表设置为 AddProduct 方法 (单击以查看全尺寸图像)

将“删除”选项卡的“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:详细信息视图当前以 Read-Only 模式呈现 (单击以查看全尺寸图像)

为了在插入模式下显示 DetailsView,我们需要将 DefaultMode 属性设置为 Inserting。 这会在首次访问时以插入模式呈现 DetailsView,并在插入新记录后将其保留在那里。 如图 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 所示,除 、 ProductNameUnitPrice 之外ProductID的所有新产品列都具有NULL值。

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

图 19:“详细信息”视图中未提供的产品字段是分配 NULL 值 (单击以查看全尺寸图像)

我们可能希望为其中一个或多个列值提供默认值, NULL 因为 NULL 不是最佳默认选项,或者数据库列本身不允许 NULL 。 为此,我们可以以编程方式设置 DetailsView InputParameters 集合的参数值。 可以在 DetailsView 事件 ItemInserting 或 ObjectDataSource Inserting 事件的事件处理程序中完成此分配。 由于我们已经了解了在数据 Web 控件级别使用前级和级别后事件,因此这次我们来探讨如何使用 ObjectDataSource 的事件。

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

在本教程中,假设应用程序在通过此接口添加新产品时,应为其分配 一个 CategoryIDSupplierID 值 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 的事件中自定义输入参数或完全取消数据修改操作。 在下一教程中,我们将介绍如何为后级别事件创建和使用事件处理程序。

编程愉快!

关于作者

Scott Mitchell 是七本 ASP/ASP.NET 书籍的作者, 4GuysFromRolla.com 的创始人,自 1998 年以来一直从事 Microsoft Web 技术工作。 Scott 担任独立顾问、培训师和作家。 他的最新书是 山姆斯在24小时内 ASP.NET 2.0自学。 可以在 上联系 mitchell@4GuysFromRolla.com他, 也可以通过他的博客联系到他,该博客可在 http://ScottOnWriting.NET中找到。

特别感谢

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