ButtonID="UpdateProduct"runat="server"CommandName="Update"
Text="Update"/>
ButtonID="CancelUpdate"runat="server"CommandName="Cancel"
Text="Cancel"/>
DataList>
ObjectDataSourceID="ProductsDataSource"runat="server"
SelectMethod="GetProducts"TypeName="ProductsBLL"
OldValuesParameterFormatString="original_{0}">
ObjectDataSource>
注意:
本章里DataList的viewstate必须开启。
浏览一下页面,见图2。
图2:
每个Product都包含一个EditButton
现在Editbutton只是引起一个postback—还不能将product变成可编辑的。
为了实现编辑功能,我们需要为EditCommand,CancelCommand和UpdateCommand创建事件处理。
EditCommand和CancelCommand事件仅仅只需要更新DataList的EditItemIndex属性,并重新绑定数据到DataList。
C#
protectedvoidProducts_EditCommand(objectsource,DataListCommandEventArgse)
{
//SettheDataList'sEditItemIndexpropertytothe
//indexoftheDataListItemthatwasclicked
Products.EditItemIndex=e.Item.ItemIndex;
//RebindthedatatotheDataList
Products.DataBind();
}
protectedvoidProducts_CancelCommand(objectsource,DataListCommandEventArgse)
{
//SettheDataList'sEditItemIndexpropertyto-1
Products.EditItemIndex=-1;
//RebindthedatatotheDataList
Products.DataBind();
}
UpdateCommand事件处理稍微麻烦一点。
它需要从DataKey集合里读取被编辑的product的ProductID,和EditItemTemplate里的TextBox里的product的name和price,然后调用ProductsBLL类的UpdateProduct方法,最后返回到DataList编辑前的状态。
我们在这里使用综叙:
在DataList里编辑和删除数据里的UpdateCommand事件处理代码。
C#
protectedvoidProducts_UpdateCommand(objectsource,DataListCommandEventArgse)
{
//ReadintheProductIDfromtheDataKeyscollection
intproductID=Convert.ToInt32(Products.DataKeys[e.Item.ItemIndex]);
//Readintheproductnameandpricevalues
TextBoxproductName=(TextBox)e.Item.FindControl("ProductName");
TextBoxunitPrice=(TextBox)e.Item.FindControl("UnitPrice");
stringproductNameValue=null;
if(productName.Text.Trim().Length>0)
productNameValue=productName.Text.Trim();
decimalunitPriceValue=null;
if(unitPrice.Text.Trim().Length>0)
unitPriceValue=Decimal.Parse(unitPrice.Text.Trim(),System.Globalization.NumberStyles.Currency);
//CalltheProductsBLL'sUpdateProductmethod...
ProductsBLLproductsAPI=newProductsBLL();
productsAPI.UpdateProduct(productNameValue,unitPriceValue,productID);
//ReverttheDataListbacktoitspre-editingstate
Products.EditItemIndex=-1;
Products.DataBind();
}
在有非法输入的时候—可能是不正确的price格式,比如“-$5.00”,或者忽略了product的name—就会引起异常。
由于UpdateCommand事件处理还没有处理异常,页面会出现ASP.NET运行时错误。
见图3。
图3:
未处理异常发生时,用户会看到这样的错误页面
第二步:
在UpdateCommandEventHandler里处理异常
更新流程中,异常可能发生在UpdateCommand事件处理,或BLL或DAL里。
比如,如果用户输入了一个“太贵”的价格,UpdateCommand事件处理里的Decimal.Parse会抛出FormatException异常。
如果用户忽略了product的name或者price是一个负数,DAL会抛出异常。
当异常发生时,我们希望显示自己定义的信息。
添加一个ID为ExceptionDetails的Label控件到页面上,通过设置CssClass属性为WarningCSS类来将Text设置为红色,特大,加粗的意大利字体。
这个类在Styles.css文件里定义。
异常发生时,我们只希望这个Label显示一次。
也就是说,在后面postback的时候,Label的警告信息需要隐藏起来。
这个可以通过清除Label的Text属性或者将Visible属性设为False(在Page_Load里)(如我们在在ASP.NET页面中处理BLL/DAL层的异常里做的那样)或者禁用Label的viewstate来实现。
我们这里用后一种方法。
ASP.NET
LabelID="ExceptionDetails"EnableViewState="False"CssClass="Warning"
runat="server"/>
异常发生时,我们将异常的信息显示在Label的Text属性上。
由于viewstate被禁用了,后面再postback的话,Text属性会自动的丢失,回到缺省值(空字符串),这样就隐藏了警告信息。
异常发生时将信息显示在页面上,我们需要在UpdateCommand事件处理里添加Try....Catch块。
Try的那部分包含可能抛出异常的代码,Catch部分包含当出现异常时需要执行的代码。
更多的Try..Catch块信息参考ExceptionHandlingFundamentals。
C#
protectedvoidProducts_UpdateCommand(objectsource,DataListCommandEventArgse)
{
//Handleanyexceptionsraisedduringtheeditingprocess
try
{
//ReadintheProductIDfromtheDataKeyscollection
intproductID=Convert.ToInt32(Products.DataKeys[e.Item.ItemIndex]);
...Somecodeomittedforbrevity...
}
catch(Exceptionex)
{
//TODO:
DisplayinformationabouttheexceptioninExceptionDetails
}
}
无论Try块里抛出何种类型的异常,Catch块的代码都会执行。
抛出异常的类型—DbException,NoNullAllowedException,ArgumentException等—取决于第一个错误。
如果是数据库级别的问题,会抛出DbException。
如果是UnitPrice,UnitsInStock,UnitsOnOrder,或ReorderLevel字段有非法值,会抛出ArgumentException(我们在ProductsDataTable里已经添加过验证字段值的代码,见创建一个业务逻辑层)
我们可以根据捕捉到的异常的类型来为用户提供更好的帮助。
下面的代码—和在ASP.NET页面中处理BLL/DAL层的异常中基本上一样—提供了这个功能:
C#
protectedvoidProducts_UpdateCommand(objectsource,DataListCommandEventArgse)
{
//Handleanyexceptionsraisedduringtheeditingprocess
try
{
//ReadintheProductIDfromtheDataKeyscollection
intproductID=Convert.ToInt32(Products.DataKeys[e.Item.ItemIndex]);
...Somecodeomittedforbrevity...
}
catch(Exceptionex)
{
//TODO:
DisplayinformationabouttheexceptioninExceptionDetails
}
}
最后仅仅只需要调用DisplayExceptionDetails方法。
完成Try..Catch后,用户会看到更有用的错误信息,如图4,5所示。
注意在异常出现时,DataList仍然保持在可编辑的模式下。
这是因为异常发生时,控制流程马上转到Catch块里,忽略了将DataList转到编辑前状态的代码。
图4:
用户忽略了必填字段时的错误信息
图5:
输入非法价格时的错误信息
总结
GridView和ObjectDataSource提供了在更新和删除过程中包含异常信息的事件处理和指明异常是否被处理的属性。
而直接使用BLL的DataList没有这些特性,我们需要亲自处理这些异常。
本章我们学习了如何在DataList的更新过程中在UpdateCommand里添加Try...Catch块来处理异常。
如果有任何异常发生,Catch块里的代码会执行,将错误信息显示在ExceptionDetailsLabel上。
现在,DataList并没有在第一时间阻止异常的发生。
尽管我们知道一个负的price值会产生异常,我们也没有添加阻止用户输入这样的值的功能。
在后面的几章里,我们将学习如何通过在EditItemTemplate里添加验证控件来验证用户的输入从而减少这些异常的发生。