导言
当使用 GridView 、 DetailsView 或 FormView 控件的内建插入、编辑或删除特征时,在用户添加一条新记录或更新 / 删除一条现在记录的过程中发生了多个步骤。正如我们之前一节里所讨论的,在 GridView 中编辑一行时,保存( Update )和取消( Cancel )按钮将取代编辑( Edit )按钮,并且绑定列转换成 TextBox 。在用户更新了数据并点击保存按钮之后,下述步骤在回传时执行:
1. 该 GridView 控件根据当前编辑行的唯一标识字段(通过 DataKeyNames 属性)组装它的 ObjectDataSource 的 UpdateParameters 参数,连同用户输入的值
2. 该 GridView 控件调用它的 ObjectDataSource 的 Update() 方法,它转而调用潜在对象的适当的方法( ProductsDAL.UpdateProduct ,我们之前一节里)
3. 现在,这些隐含的数据,包含保存后的更改,被重新绑定到 GridView 控件
在这一连串的步骤里,触发了许多事件,这让我们可以创建事件处理程序从而在需要的地方增加自定义逻辑。例如,在第 1 步之前,触发 GridView 的事件。在这里,如果有什么 validation 错误我们可以取消更新请求。当调用 Update() 方法时,触发 ObjectDataSource 的 Updating 事件,提供了增加或自定义 UpdateParameters 的值的机会。在 ObjectDataSource 的潜在对象的方法完全执行后,触发 ObjectDataSource 的 Updated 事件。针对 Updated 事件的事件处理程序可以检查更新操作的相关详细信息,例如影响了多少行数据,或者是否引发了一个异常。最后,在第 2 步之后, GridView 的 RowUpdated 事件触发;针对此事件的事件处理程序可以检查关于刚刚完成的更新操作的相关额外信息。
图 1 描述了使用 GridView 更新时这一系列连续的事件和步骤。图 1 里的这个事件模式不仅是在 GridView 的更新操作。从 GridView 、 DetailsView 或者 FormView 里插入、更新或者删除数据时,数据 Web 服务器控件和 ObjectDataSource 都会发生这一连串的 pre-level 和 post-level 的事件。
图
1:
当在
GridView
里更新数据时,触发一连串的
Pre-
和
Post-
事件
在这一节里,我们将探讨使用这些事件从而扩展 ASP.NET 数据 Web 服务器控件的内建插入、更新和删除功能。我们也会看看如何自定义编辑界面从而仅仅更新部分产品字段。
第一步 : 更新产品的 ProductName 和 UnitPrice 字段
在之前一节的编辑界面里,包含了产品的所有字段并且它们都不是只读的。如果我们从 GridView 中剔除一列( QuantityPerUnit ),那么当更新时数据 Web 服务器控件就不会设置 ObjectDataSource 的 QuantityPerUnit UpdateParameters 的值。 ObjectDataSource 则传入一个 null 值到 UpdateProduct 这个业务逻辑层的方法,它将当前编辑的数据库记录的 QuantityPerUnit 字段更改为值。同样地,如果是一个必需的字段,例如 ProductName ,如果从编辑界面中剔除了,那么此更新将会失败并抛出一个 “ Column 'ProductName' does not allow nulls ” 异常。导致这一现象的原因是 ObjectDataSource 被配置为调用 ProductsBLL 类的 UpdateProduct 方法,它预期每一个产品字段都对应一个输入参数。因此, ObjectDataSource 的 UpdateParameters 集合包含了该方法的每一个输入参数。
如果我们希望提供一个允许最终用户仅仅可以更新部分字段的数据 Web 服务器控件,那么我们需要在 ObjectDataSource 的 Updating 事件处理程序中编程设置缺失的 UpdateParameters 值,或者创建并调用一个预期部分字段的 BLL 方法。让我们在接下来的步骤中探讨。
特别地,让我们创建一个在一个可编辑的 GridView 中仅显示 ProductName 和 UnitPrice 字段的页面。这个 GridView 的编辑界面将仅仅允许用户更新两个显示的字段, ProductName 和 UnitPrice 。因为这个编辑界面仅仅提供产品的部分字段,我们需要创建一个 ObjectDataSource ,它使用现有的 BLL 的 UpdateProduct 方法并在 Updating 事件处理程序中编程设置产品的缺少的字段的值,或者我们需要创建一个新的 BLL 方法,它仅接受那些在 GridView 中已经定义的部分字段。在这一节里,我们使用后者,创建一个 UpdateProduct 方法的重载,它提取 3 个输入参数: 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 字段并通过调用 TableAdapter 的 Update() 方法提交此更新,传入 ProductsRow 实例。
通过这些对我们的 ProductsBLL 类的额外处理,我们现在可以创建一个简单 GridView 界面。打开 EditInsertDelete 文件夹中的 DataModificationEvents.aspx ,添加一个 GridView 控件到页面。新建一个 ObjectDataSource 并配置它使用 ProductsBLL 类,它的 Select() 方法映射到 GetProducts , Update() 方法映射到仅接受 productName 、 unitPrice 和 productID 输入参数的 UpdateProduct 方法重载。图 2 展示了映射 ObjectDataSource 的 Update() 方法到 ProductsBLL 类的新的 UpdateProduct 方法重载时的数据源配置向导。
图
2:
映射
ObjectDataSource
的
Update()
方法到新的
UpdateProduct
重载
因为我们的例子将仅仅需要编辑数据的能力,不需要插入或删除记录,那么花些时间明确地指明该 ObjectDataSource 的 Insert() 和 Delete() 方法不会映射到 ProductsBLL 类的任何方法 -- 通过到 INSERT 和 DELETE 的 tab 页并从下拉列表中选择(无)。
图
3:
在
INSERT
和
DELETE
的
Tab
页,从下拉列表中选择(无)
完成了此向导后,从 GridView 的职能标记里勾选上启用编辑。
完成了此数据源配置向导并绑定到 GridView 后, Visual Staudio 就已经添加好它们的声明语法。到源视图察看该 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 片段。此外,因为方法映射到 UpdateProduct 方法重载,它仅接受 3 个输入参数, UpdateParameters 片段也就仅包含 3 个 Parameter 实例。
注意到 ObjectDataSource 的属性被设置为 original_{0} 。这个属性是使用数据源配置向导时 Visual Studio 自动设置的。因此,由于我们的 BLL 方法不需要传入原始的 ProductID 值,从 ObjectDataSource 的声明语法中删除所有这些属性设置。
注意 : If you 如果你只是简单地在设计视图里从属性窗口清除 OldValuesParameterFormatString 属性的值,这个属性会依旧存在于声明语法里,但会被设置为一个空字符串。要么从声明语法里把该属性通通删掉,要么从属性窗口,设置它的值为默认值: {0} 。
虽然 ObjectDataSource 仅仅包含对 productName 、 unitPrice 和 productID 的 UpdateParameters , Visual Studio 还是为产品的每一个字段添加一个绑定列或 CheckBoxField 。
图
4:
对应产品的每一个字段,
GridView
都包含一个
BoundField
或
CheckBoxField
当最终用户编辑一个产品并点击它的保存按钮( Update ),该 GridView 遍历那些可编辑的字段,然后把用户输入的值赋值到 ObjectDataSource 的 UpdateParameters 集合里对应的参数。如果没有对应的参数, GridView 则添加一个到参数集合里。因此,如果我们的 GridView 包含对应产品的所有字段的绑定列或 CheckBox 列,那么 ObjectDataSource 则会调用能接受这些参数的方法重载,而不顾 ObjectDataSource 的声明标记指定只接受 3 个输入参数的事实(见图 5 )。类似地,如果存在某些由 GridView 非只读列构成的组合,而没有一个 UpdateProduct 重载能接受相应的参数,则会在试图保存时引发一个异常。
图
5: GridView
将添加参数到
ObjectDataSource
的
UpdateParameters
集合
为了确保 ObjectDataSource 调用仅接受 productName 、 unitPrice 和 productID 参数 的 UpdateProduct 重载,我们需要限定 GridView 仅包含 ProductName 和 UnitPrice 这两个可编辑的列。这可以通过删除其他绑定列和 CheckBox 列,或者把这些列的 ReadOnly 属性设置为 true 实现,又或者上述两种方法结合使用。在本节里让我们简单地删除除了 ProductName 和 UnitPrice 绑定列以外的 GridView 的所有列,然后, GridView 的声明标记将如下所示:
<asp:GridView ID="GridView1" runat="server" AutoGenerateColumns="False" DataKeyNames="ProductID" DataSourceID="ObjectDataSource1" EnableViewState="False">
<Columns>
<asp:CommandField ShowEditButton="True" />
<asp:BoundField DataField="ProductName" HeaderText="ProductName" SortExpression="ProductName" />
<asp:BoundField DataField="UnitPrice" HeaderText="UnitPrice" SortExpression="UnitPrice" />
</Columns>
</asp:GridView>
即使重载预期 3 个输入参数,在我们的 GridView 里仅包含两个绑定列。这是因为 productID 输入参数是一个主键( primary key )的值,它通过当前编辑行的 DataKeyNames 属性传入值。
我们的 GridView 控件,连同这个 UpdateProduct 重载,允许一个用户仅仅编辑产品的名称和单价而不会丢失产品的其他字段。
图
6:
仅允许编辑
ProductName
和
Unit
Price
的界面
完善 UnitPrice 格式化
虽然图 6 所示的 GridView 实例能够正常工作, UnitPrice 字段还完全未被格式化,导致显示价格时缺少货币符号,还有 4 个小数位。为了在非编辑状态的行应用货币格式,只需要简单地设置 UnitPrice 绑定列的 DataFormatString 属性为 {0:c} ,还有它的 HtmlEncode 属性为 false 。
图
7:
设置
UnitPrice
绑定列的
DataFormatString
和
HtmlEncode
属性
通过此项更改,处于非编辑状态的行将价格格式化为货币;然而,当前编辑的行,仍然显示为没有货币符号并保留四位小数。
图
8:
现在,非编辑状态的行格式化为货币值
通过设置此绑定列的 ApplyFormatInEditMode 属性为 true (默认为 false ),可以把 DataFormatString 属性里指定的格式化指令应用到编辑界面。
图
9:
设置此绑定列的
ApplyFormatInEditMode
属性为
true
通过这个更改,当前编辑行里显示的 UnitPrice 值也被格式化为货币。
图
10:
现在,当前编辑行的值也被格式化为货币
然而,如果把产品价格更新为文本框里带货币符号的值 – 例如 $19.00 – 则会抛出一个 FormatException 异常。当 GridView 尝试把用户提供的值赋值到 ObjectDataSource 的 UpdateParameters 集合,它无法把 UnitPrice 字符串“ $<chmetcnv w:st="on" unitname="”" sourcevalue="19" hasspace="False" negative="False" numbertype="1" tcsc="0">19.00<span><span>”</span></span></chmetcnv> 转换成参数要求的 decimal 类型(见图 11 )。为了补救这个问题我们可以为 GridView 的 RowUpdating 事件添加一个事件处理程序并让它把用户输入的 UnitPrice 格式化为货币格式的 decimal 。
这个 GridView 的 RowUpdating 事件接受的第二个参数是一个 GridViewUpdateEventArgs 类型的对象,它包含一个 NewValues 字典,当中的每一个属性保存着用户输入的值,准备赋值到 ObjectDataSource 的 UpdateParameters 集合。我们可以重写现有的 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);
}
如果用户提供了一个诸如“ $<chmetcnv w:st="on" unitname="”" sourcevalue="19" hasspace="False" negative="False" numbertype="1" tcsc="0">19.00<span><span>”</span></span></chmetcnv> 的 UnitPrice 值,这个值会被通过 Decimal.Parse 计算并解析为货币金额的值重写。这将正确的解析货币值,无论是货币符号、逗号、小数点、等等,并使用 System.Globalization 命名空间的 NumberStyles 枚举 。
图 11 展示因用户输入的 UnitPrice 值带有货币符号引起的问题,还展示了如果利用 GridView 的 RowUpdating 事件处理程序从而正确地解析这样的输入。
图
11:
现在,当前编辑行的
UnitPrice
值被格式化为货币金额
第二步 : 阻止 NULL UnitPrices
虽然数据库被配置为允许 Products 表里的 UnitPrice 字段为 NULL 值,但我们可能希望防止用户访问这个特别的页面并指定一个空的 UnitPrice 值。更确切地说,如果用户在编辑一个产品行记录时忘记输入一个 UnitPrice 值, 与其保存这个结果到数据库,我们还不如给用户显示一个提示信息,自始至终这个页面,任何的对产品的编辑必须指定一个价格。
传入到 GridView 的事件处理程序的 GridViewUpdateEventArgs 对象包含一个 Cancel 属性,如果把它设置为 true ,则中止这个更新过程。让我们扩展 RowUpdating 事件处理程序,设置 e.Cancel 为 true 并显示一个信息说明为什么在 NewValues 集合里的 UnitPrice 值为 null 。
首先,添加一个 Label 服务器控件到页面并命名为 MustProvideUnitPriceMessage 。这个 Label 控件将显示用户是否在更新一个产品时忘记指定一个 UnitPrice 值。设置这个 Label 的 Text 属性为“您必须为产品提供一个价格。”。我也已经在 Styles.css 文件中添加了一个名为 Warning 的新 CSS 类别,定义如下:
.Warning
{
color: Red;
font-style: italic;
font-weight: bold;
font-size: x-large;
}
最后,设置 Label 的 CssClass 属性为 Warning 。这样设计器中将在 GridView 上方显示这个红色、斜体、加粗、并且较大字体的警告信息。
图
12:
一个
Label
控件已被添加到
GridView
上方
默认地,这个 Label 控件隐藏,那么在 Page_Load 事件处理程序中设置它的 Visible 属性为 false 。
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;
}
}
如果一个用户试图保存一个产品并不指定价格,这个更新操作就被取消并显示一个有用的提示信息。虽然数据库(和业务逻辑)允许 NULL 值的 UnitPrice ,但这个特定的 ASP.NET 页面不允许。
图
13:
用户不能让
UnitPrice
为空
到目前为止我们看过了如何使用 GridView 的 RowUpdating 事件来编程改变赋值到 ObjectDataSource 的 UpdateParameters 集合的参数值,还有如何完全地取消这个更新过程。这些思想也可以延展至 DetailsView 和 FormView 控件并且应用到插入或删除。
这些任务也可以在 ObjectDataSource 这一层通过的 Inserting 、 Updating 和 Deleting 事件处理程序完成。这些事件在隐含对象的关联方法被调用前触发,并且提供一个更改输入参数集合或者完全取消此操作的最后机会。对应这 3 个事件的事件处理程序传入一个 ObjectDataSourceMethodEventArgs 类型的对象,我们对它的这两个属性感兴趣:
· Cancel ,它如果被设置为 true ,取消执行中的操作
· InputParameters ,它是 InsertParameters 、 UpdateParameters 或 DeleteParameters 的集合,这取决于这是 Inserting 、 Updating 、 还是 Deleting 事件的事件处理程序
为了举例说明在 ObjectDataSource 这一层如何处理参数的值,让我们在页面里包含一个 DeailsView ,它允许用户新增一个新的产品记录。这个 DetailsView 将用作提供一个快捷的方式添加一个新的产品记录到数据库。为了在新增产品时保持界面一致,我们仅允许用户输入 ProductName 和 UnitPrice 字段。作为默认值,这些在 DetailsView 的插入界面提供的值将被设置为一个数据库的 NULL 值。不过,我们可以使用 ObjectDataSource 的 Inserting 事件注入不同的默认值,正如我们马上要看的。
第三步 : 提供一个添加新产品的界面
在 GridView 的上方,从工具箱里拖放一个 DetailsView 控件到设计器,清空它的 Height 和 Width 属性,并将它绑定到页面中已经存在的 ObjectDataSource 。这将为产品的每一个字段添加一个绑定列或 CheckBox 列。因为我们希望用这个 DetailsView 控件来添加新产品,我们需要从它的职能标记里勾选启用插入这一项;然而并没有这一项,这是因为此 ObjectDataSource 的 Insert() 方法还没有映射到 ProductsBLL 类的方法(回想起我们在配置数据源时设置了这个映射为(无) – 见图 3 )。
为了再次配置这个 ObjectDataSource ,从它的职能标记中选择“配置数据源”的链接,载入向导。第一屏允许你更改 ObjectDataSource 绑定到的隐含对象;让它依旧是 ProductsBLL 。下一屏列出从 ObjectDataSource 到隐含对象的方法的映射。尽管我们已经明确地指定 Insert() 和 Delete() 不映射到任何方法,然而如果你到 INSERT 和 DELETE 的 tab 页你还是会看到那里有一个映射。这是因为 ProductsBLL 的 AddProduct 和 DeleteProduct 方法使用了 DataObjectMethodAttribute 指出它们分别是为 Insert() 和 Delete() 服务的默认的方法。因此, ObjectDataSource 向导在每次运行时都会自动地选择它们,除非那里被明确地指定了一个别的值。
让 Insert() 方法依旧指向 AddProduct 方法,不过再次从 DELETE 的 tab 页的下拉列表中选择“ ( 无 ) ”。
图
14:
从
INSERT
的
Tab
页的下拉列表中选择
AddProduct
方法
图
15:
从
DELETE
的
Tab
页的下拉列表中选择
(
无
)
完成了这些更改后,该 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 的职能标记里包含“启用插入”的 checkbox ;回到设计器并勾选这一项。然后,减少 DetailsView 的列直道它只包含两个绑定列 - ProductName 和 UnitPrice ,还有一个 CommandField 。此时 DetailsView 的声明语法将如下所示:
<asp:DetailsView ID="DetailsView1" runat="server" AutoGenerateRows="False" DataKeyNames="ProductID" DataSourceID="ObjectDataSource1" EnableViewState="False">
<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
提供了一个快速添加新产品的界面
当用户输入一个产品名称和价格(例如“ Acme Wate ”和 1.99 ,如图 17 )并点击插入按钮,发生回传并且开始插入的工作流程,直到最后添加一个新产品记录到数据库。 DetailsView 维持在它的插入界面,并且 GridView 自动地重现绑定到它的数据源,目的是为了包含新增加的产品,如图 18 所示。
图
18:
产品“
Acme Water
”已经被添加到数据库
虽然图 18 的 GridView 中没有显示出来, DetailsView 界面里缺少的产品字段 – CategoryID 、 SupplierID 、 QuantityPerUnit 、等等 – 被赋上一个数据库 NULL 值。你可以通过履行下面一个步骤来看到这一点:
1. 到 Visual Studio 的服务器资源管理器
2. 展开 NORTHWND.MDF 数据库节点
3. 在 Products 数据表节电上右键点击
4. 选择“显示表数据”
这将列出 Products 表中的所有记录。如图 19 所示,除了 ProductID 、 ProductName 和 UnitPrice 字段,我们的新产品的其它字段都为 NULL 值。
图
19:
未在
DetailsView
中提供的产品的其它字段被赋予
NULL
值
我们可能希望给予一个或几个这些字段的值一个默认值,而不是 NULL ,要么是因为 NULL 并非最佳的默认项,要么是因为数据库字段本身不允许 NULL 值。为了实现这一点,我们可以编程设置这些 DetailsView 的 InputParameters 集合里的参数值。这项工作可以在 DetailsView 的 ItemInserting 事件处理程序中完成,或者在 ObjectDataSource 的 Inserting 事件处理程序。因为我们已经看过了如何在数据 Web 服务器控件中如何使用 pre- 和 post-level 的事件,这次让我们探究一下 ObjectDataSource 的事件。
第四步 : 给 CategoryID 和 SupplierID 参数赋值
在这里我们假设当我们的应用程序通过这个界面添加一个新产品时应该给 CategoryID 和 SupplierID 字段赋值为 1 。如之前提及的, ObjectDataSource 控件有一对 pre- 和 post-level 的事件发生在数据更改过程中。当它的 Insert() 方法被调用时, ObjectDataSource 首先触发它的 Inserting 事件,然后调用它的 Insert() 方法所映射到的业务方法,最后触发 Inserted 事件。这个 Inserting 事件处理程序提供给我们一个处理输入参数或者彻底取消此操作的最后机会。
注意 : 在一个真实的应用程序中你很可能希望既让用户指定 category 和 supplier 的值,又希望基于一定的标准和业务逻辑的基础上选择这个值(而不是盲目地选择 ID 为 1 )。不管如何,这个例子阐明了如何在 ObjectDataSource 的 pre-level 的事件中编程设置一个输入参数的值。
花些时间为 ObjectDataSource 的 Inserting 事件创建一个事件处理程序。注意到该事件处理程序的第二个输入参数是一个 ObjectDataSourceMethodEventArgs 类型的对象,它有一个属性来存取参数集合( InputParameters ),还有一个属性用来取消此操作( Cancel )。
protected void ObjectDataSource1_Inserting(object sender, ObjectDataSourceMethodEventArgs e)
{
}
此时, InputParameters 属性包含了通过 DetailsView 赋值到 ObjectDataSource 的 InsertParameters 集合。为了修改这些参数里的一个值,简单地使用: e.InputParameters[" paramName "] = value 。所以,为了设置 CategoryID 和 SupplierID 为 1 ,把 Inserting 事件处理程序调整为如下:
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-level 的事件。在这一节里,我们研究了 pre-level 的事件,并看到了如何在数据 Web 服务器控件和 ObjectDataSource 的事件里使用它们来自定义输入参数或取消当前的数据更改操作。下一节,我们将看看创建和使用 post-level 的事件的事件处理程序。
祝编程快乐!
作者简介
Scott Mitchell ,著有六本 ASP/ASP.NET 方面的书,是 4GuysFromRolla.com 的创始人,自 1998 年以来一直应用微软 Web 技术。 Scott 是个独立的技 术咨询顾问,培训师,作家,最近完成了将由 Sams 出版社出版的新作, 24 小时内精通 ASP.NET 2.0 。他的联系电邮为 mitchell@4guysfromrolla.com ,也可以通过他的博客 http://ScottOnWriting.NET 与他联系。