当前位置: 移动技术网 > IT编程>开发语言>.net > 在ASP.NET 2.0中操作数据之三十六:在DataList里编辑和删除数据概述

在ASP.NET 2.0中操作数据之三十六:在DataList里编辑和删除数据概述

2017年12月12日  | 移动技术网IT编程  | 我要评论

蘑菇街陈琪,火灭网,膨胀螺钉规格

导言

  概述插入、更新和删除数据 里我们已经学习了如何使用gridview等控件来插入,更新删除数据。通过objectdatasource和其它数据控件仅仅只需要在智能标签里勾一下checkbox就完成了,不需要写任何代码。而datalist没有这些内置的功能。我们可以使用1.x 里的方法来实现这些功能。在本章我们将看到,datalist提供了一些事件和属性来完成我们的目的,为此我们需要写一些代码。

  本章我们首先学习如何创建一个支持编辑和删除数据的datalist。后面的教程里我们将学习一些高级的编辑和删除方法,包括验证,dal和bll的异常处理等。

  注意:和datalist一样,repeater也不提供内置的这些功能。而且repeater里没有datalist里提供的那些事件和属性。因此本章和后面的几章我们仅仅只讨论datalist。

第一步: 创建编辑和删除教程页

  首先创建本章和后面几章需要用到的页。添加一个名为editdeletedatalist的文件夹。然后添加下面的页。确保每页都包含了site.master。

default.aspx
basics.aspx
batchupdate.aspx
errorhandling.aspx
uivalidation.aspx
customizedui.aspx
optimisticconcurrency.aspx
confirmationondelete.aspx
userlevelaccess.aspx

http://www.lhsxpumps.com/_images/10qianwan/20171212/b_1_201712121909236695.jpg
图 1: 添加页

  和别的文件夹一样,default.aspx列出教程章节。记得sectionleveltutoriallisting.ascx用户控件提供了这个功能。从解决方案里将它拖到我们的页里。

http://www.lhsxpumps.com/_images/10qianwan/20171212/b_1_201712121909236508.jpg
图 2: 添加sectionleveltutoriallisting.ascx 用户控件

  最后将这些页添加到web.sitemap里。在master/detail reports with the datalist and repeater<sitemapnode>之后添加下面的标记:

<sitemapnode
 title="editing and deleting with the datalist"
 description="samples of reports that provide editing and deleting capabilities"
 url="~/editdeletedatalist/default.aspx" >
 <sitemapnode
 title="basics"
 description="examines the basics of editing and deleting with the
   datalist control."
 url="~/editdeletedatalist/basics.aspx" />
 <sitemapnode
 title="batch update"
 description="examines how to update multiple records at once in a
   fully-editable datalist."
 url="~/editdeletedatalist/batchupdate.aspx" />
 <sitemapnode
 title="error handling"
 description="learn how to gracefully handle exceptions raised during the
   data modification workflow."
 url="~/editdeletedatalist/errorhandling.aspx" />
 <sitemapnode
 title="adding data entry validation"
 description="help prevent data entry errors by providing validation."
 url="~/editdeletedatalist/uivalidation.aspx" />
 <sitemapnode
 title="customize the user interface"
 description="customize the editing user interfaces."
 url="~/editdeletedatalist/customizedui.aspx" />
 <sitemapnode
 title="optimistic concurrency"
 description="learn how to help prevent simultaneous users from
   overwritting one another s changes."
 url="~/editdeletedatalist/optimisticconcurrency.aspx" />
 <sitemapnode
 title="confirm on delete"
 description="prompt a user for confirmation when deleting a record."
 url="~/editdeletedatalist/confirmationondelete.aspx" />
 <sitemapnode
 title="limit capabilities based on user"
 description="learn how to limit the data modification functionality
   based on the user s role or permissions."
 url="~/editdeletedatalist/userlevelaccess.aspx" />
</sitemapnode>

更新了web.sitemap后,浏览一下。

http://www.lhsxpumps.com/_images/10qianwan/20171212/b_1_201712121909232023.jpg
图 3: 站点导航现在包含了编辑和删除datalist 教程

第二步: 探讨更新和删除数据所要用到的技术

  使用gridview来编辑和删除数据之所以很简单,是因为gridview和objectdatasource在底层非常一致。如研究插入、更新和删除的关联事件里所讨论的,当更新按钮被点击时,gridview自动将字段的值赋给objectdatasource的updateparameters集合,然后激发objectdatasource的update()方法。我们现在需要确保将合适的值赋给objectdatasource的参数,然后调用update()方法。datalist提供了以下的属性和事件来帮助我们完成这些:

  datakeyfield property — 更新或删除时,我们需要唯一确定datalist里的每个item。将这个属性设为显示的数据的主健。这样做会产生datalist的 datakeys collection ,每个item都有一个指定的 datakeyfield .
 editcommand event — 当commandname属性设为“edit”的button, linkbutton, 或 imagebutton 被点时激发.
 cancelcommand event — 当commandname属性设为“cancel”的button, linkbutton, 或 imagebutton 被点时激发. updatecommand event — 当commandname属性设为“update”的button, linkbutton, 或 imagebutton 被点时激发.  deletecommand event — 当commandname属性设为“delete”的button, linkbutton, 或 imagebutton 被点时激发.

  使用以上的属性和事件,我们有四种方法来更新和删除数据:

  使用asp.net 1.x 的技术— datalist先于asp.net 2.0 和objectdatasources 存在,可以直接通过编程来实现编辑和删除。这种方法需要我们在显示数据或者更新删除记录时,直接在bll层将数据绑定到datalist。
使用一个单独的objectdatasource 来实现选择,更新和删除 — datalist没有gridview内置的编辑删除功能,并不意味着我们不能添加这些功能。我们象在gridview的例子里那样,使用 objectdatasource,但是在设置objectdatasource的参数并调用update()方法时,需要为datalist的updatecommand事件创建一个  event handler。 using an objectdatasource control for selecting, but updating and deleting directly against the bll — 使用第二种方法时我们需要为updatecommand事件和参数赋值等写一些代码。其实我们可以用objectdatasource来实现selecting ,更新和删除直接调用bll(象第一种方法)。我的意见是,直接调用bll会使代码可读性更好。 使用多个objectdatasources —前面的三种方法都需要一些代码。如果你宁愿坚持使用尽可能多的声明语法的话,最后一种方法是使用多个objectdatasources 。第一个objectdatasource 从bll获取数据,并绑定到 datalist. 为更新添加另一个 objectdatasource, 直接添加到 datalist的 edititemtemplate.同样对删除也是如此。三个 objectdatasource通过 controlparameters   声明语法直接将参数绑定到objectdatasource 的参数 (而不是在 datalist的 updatecommand event handler编程处理). 这种方法也需要一些编码 — 我们需要调用 objectdatasource内置的 update() 或 delete() — 但是比起其它三种方法,代码少的多。这种方法的劣势是多个  objectdatasources 使页面看起来混乱。

   我喜欢选择第一种方法,因为它提供了更好的可扩展性,而设计datalist的本意就是使用这种方式。当扩展datalist使它和asp.net 2.0的数据源控件一起工作时,它没有“正式”的asp.net 2.0数据控件( gridview, detailsview, 和formview)的那些可扩展性或特性。当然其它方法也不是没有优点。

  这几章关于编辑和删除的教程会使用objectdatasource 来显示数据,然后直接调用bll来实现编辑和删除(第三种方法)

第三步: 添加datalist并配置它的objectdatasource

  本章我们将创建一个datalist用来列出product的信息,并提供用户编辑其name和price,删除的功能。我们使用objectdatasource来显示数据,调用bll来实现更新和删除的功能。首先我们来实现一个只读的显示product的页。由于在前面的教程里已经实现过这样的功能,在这里我们很快带过。

  打开editdeletedatalist文件夹下的basics.aspx页,添加一个datalist。然后通过智能标签创建一个objectdatasource。在select标签里使用productsbll类的getproducts()方法配置它。

http://www.lhsxpumps.com/_images/10qianwan/20171212/b_1_201712121909233308.jpg
图 4: 使用productbll类配置objectdatasource

http://www.lhsxpumps.com/_images/10qianwan/20171212/b_1_201712121909206734.jpg
图 5: 选择getproducts()

在insert,update和delete标签里都选择none。

http://www.lhsxpumps.com/_images/10qianwan/20171212/b_1_201712121909249108.jpg
图 6: 在insert, update, 和delete 标签里选择(none)

  完成配置后回到设计界面。如我们在以前的例子里看到的那样,visual studio 会自动创建itemtemplate,显示数据。将itemtemplate改为只显示product的name和price。然后将repeatcolumns设为2。

  注意:象以前讨论的那样,当使用objectdatasource修改数据时,我们在声明标记里需要移除oldvaluesparameterformatstring (或重新设为缺省值,{0})。而本章objectdatasource仅仅只用来获取数据,因此不需要那样做(当然那样做了也没关系)。完成后你的页代码看起来应该和下面差不多:

<asp:datalist id="datalist1" runat="server" datakeyfield="productid"
 datasourceid="objectdatasource1" repeatcolumns="2">
 <itemtemplate>
 <h5>
  <asp:label runat="server" id="productnamelabel"
  text='<%# eval("productname") %>'></asp:label>
 </h5>
 price: <asp:label runat="server" id="label1"
   text='<%# eval("unitprice", "{0:c}") %>' />
 <br />
 <br />
 </itemtemplate>
</asp:datalist>
<asp:objectdatasource id="objectdatasource1" runat="server"
 selectmethod="getproducts" typename="productsbll"
 oldvaluesparameterformatstring="original_{0}">
</asp:objectdatasource>

浏览一下页面。如图7,datalist以两列的方式显示product的name和price。

http://www.lhsxpumps.com/_images/10qianwan/20171212/b_1_201712121909241395.jpg
图 7:  datalist显示products的 names and prices

  注意:datalist有一些属性是编辑和删除需要用到的,这些值都存在view state里。因此创建支持编辑和删除功能的datalist时,datalist的view state需要开启。

  聪明的读者应该记起来在创建可编辑的gridview,detailsviews和formviews的时候,view state是禁用的。这是因为asp.net 2.0 控件包含了control state,它在postback时状态是连续的。

  在gridview里禁用了view state仅仅只是忽略了无关紧要的状态信息,但是维持了control state(它包含了编辑和删除需要的状态)。而datalist是 asp.net 1.x时代创建的,并没有使用control state,因此view state必须开启。更多的control state的目的以及和view state的区别信息见control state vs. view state

第四步: 添加一个编辑界面

  gridview控件是由字段集合组成的(boundfields, checkboxfields, templatefields等)。这些字段能根据模式来调整标记。比如,在只读模式下,boundfield 将字段值显示为文本,而在编辑模式下,它将显示为一个textbox,这个textbox的text属性被赋予字段的值。

  另一方面,datalist用template来展现它的item。只读的item用itemtemplate来展现。而当在编辑模式下时,item用edititemtemplate来展示。现在我们的datalist只有一个itemtemplate。我们需要添加一个edititemtemplate来支持编辑功能。本章我们使用textbox来编辑product的name和price。可以通过声明语言或设计视图(datalist的智能标签的edittemplate选项)来创建edititemtemplate。

http://www.lhsxpumps.com/_images/10qianwan/20171212/b_1_201712121909242680.jpg
图 8:选择edititemtemplate


  然后输入“product name:” 和“price:” ,再拖两个textbox到edititemtemplate。将textbox的id属性设为productname和unitprice。

http://www.lhsxpumps.com/_images/10qianwan/20171212/b_1_201712121909245438.jpg
图 9:  添加textbox


  我们需要将product的字段绑定到关联的textbox。在textbox的智能标签上点击edit databindings,然后将text属性和适当的字段关联。见图10。

  注意:将unitprice绑定到textbox时,你可以用({0:c})将它 格式化为货币值,或用({0:n})表示为普通数字,或者不格式化。

http://www.lhsxpumps.com/_images/10qianwan/20171212/b_1_201712121909249952.jpg
图 10:绑定字段到textboxes


  注意:图10里的edit databindings对话框里并不包含“双向数据绑定”的checkbox,而在编辑gridview或detailsview里的templatefield,或者formview里的template里时是有这个checkbox的。双向数据绑定允许在插入或更新数据时,输入控件的值自动赋给相关联的objectdatasource的insertparameters或updateparameters。datalist并不支持双向绑定—我们在后面会看到,在用户作出更改,准备更新数据时,我们需要编程将textbox的text的值传给productsbll类的updateproduct方法。


  最后我们在edititemtemplate里加入update和cancel按钮。象前面看到的那样,当设置了commandname的repeater或datalist里的button,linkbutton或imagebutton被点击时,repeater或datalist的itemcommand事件被激发。对datalist来说,如果commandname设为某个值,另外一个事件也会被激发,如下:


“cancel” — 激发 cancelcommand event
“edit” — 激发 editcommand event
“update” — 激发updatecommand event

  记住除了itemcommand外,这些事件会激发。

  为edititemtemplate添加两个button,一个commandname设为"update",一个设为"cancel"。完成后,设计界面看起来应该和下面差不多:

http://www.lhsxpumps.com/_images/10qianwan/20171212/b_1_201712121909246253.jpg
图 11: 为 edititemtemplate 添加update 和cancel 按钮

你的标记语言看起来应该和下面差不多:

<asp:datalist id="datalist1" runat="server" datakeyfield="productid"
 datasourceid="objectdatasource1" repeatcolumns="2">
 <itemtemplate>
 <h5>
  <asp:label runat="server" id="productnamelabel"
  text='<%# eval("productname") %>' />
 </h5>
 price: <asp:label runat="server" id="label1"
   text='<%# eval("unitprice", "{0:c}") %>' />
 <br />
 <br />
 </itemtemplate>
 <edititemtemplate>
 product name:
  <asp:textbox id="productname" runat="server"
  text='<%# eval("productname") %>' /><br />
 price:
  <asp:textbox id="unitprice" runat="server"
  text='<%# eval("unitprice", "{0:c}") %>' /><br />
 <br />
 <asp:button id="updateproduct" runat="server"
  commandname="update" text="update" /> 
 <asp:button id="cancelupdate" runat="server"
  commandname="cancel" text="cancel" />
 </edititemtemplate>
</asp:datalist>
   

第五步: 添加进入编辑模式的入口

  现在我们的datalist有一个编辑界面了。然而现在还没有办法来体现出用户需要编辑product信息。我们需要为每个product加一个edit button,当点击时,将datalist item展示为编辑模式。同样的可以通过设计器或直接声明代码来添加。确保将edit button的commandname属性设为"edit".添加完后,浏览一下页面。

http://www.lhsxpumps.com/_images/10qianwan/20171212/b_1_201712121909257538.jpg
图 12: 添加edit buttons

  点击button会引起postback,但是并没有进入product的编辑模式。为了完成这个,我们需要:

  设置datalist的 edititemindex property 为 被点击了edit button的 datalistitem的 index .
  重新绑定数据到 datalist. 当 datalist 重新展现时, 和datalist的edititemindex相关的datalistitem 会展现edititemtemplate.

  由于在点edit button时,datalist的editcommand事件被激发,使用下面的代码创建一个editcommand event handler :

protected void datalist1_editcommand(object source, datalistcommandeventargs e)
{
    // set the datalist's edititemindex property to the
    // index of the datalistitem that was clicked
    datalist1.edititemindex = e.item.itemindex;
    // rebind the data to the datalist
    datalist1.databind();
}
           

  editcommand event handler 的第二个参数类型为datalistcommandeventargs ,它是被点击的edit button的datalistitem的引用(e.item).首先设置datalist的edititemindex为想编辑的datalistitem的itemindex,然后重新绑定数据。完成后再浏览页面。点edit button,现在product变成了可编辑的。见图13。

http://www.lhsxpumps.com/_images/10qianwan/20171212/b_1_201712121909253053.jpg
图 13: 点edit button 使product 可编辑

第六步: 保存用户的更改

  现在点product的update或cancel button不会有任何反应。为了完成目标我们需要为datalist的updatecommand和cancelcommand创建event handler。首先创建cancelcommand event handler,它在product的cancel button点击时执行,使datalist返回编辑之前的状态。使datalist以只读模式展示item,我们需要:

  设置datalist的 edititemindex property 为一个不存在的datalistitem index -1是一个好的选择。(由于datalistitem index从0开始) 重新绑定数据到datalist。由于没有datalistitem itemindex和datalist的edititemindex关联,整个datalist会展现为只读模式。 这些可以通过以下代码完成:

protected void datalist1_cancelcommand(object source, datalistcommandeventargs e)
{
 // set the datalist's edititemindex property to -1
 datalist1.edititemindex = -1;
 // rebind the data to the datalist
 datalist1.databind();
}

现在点击cancel button会返回到datalist编辑前的状态。

最后我们来完成updatecommand event handler,我们需要:

编程获取用户输入的product name和price,还有productid.
调用productsbll类里的合适的updateproduct重载方法.
设置datalist的edititemindex property 为一个不存在的datalistitem index. -1 是一个好的选择。
重新帮顶数据。

  第一和第二步负责保存用户的更改。第三步返回到datalist编辑前的状态(和cancelcommand event handler一样)。

  我们需要使用findcontrol方法来获取product的name和price(当然包括productid)。当最初将objectdatasource绑定到datalist时,visual studio 将datalist的datakeyfield 属性赋为数据源的主键值(productid)。这个值可以通过datalist的datakey集合来获取。花点时间验证一下datakeyfield 是否设置为productid。

下面的代码完成了上面的功能:

protected void datalist1_updatecommand(object source, datalistcommandeventargs e)
{
 // read in the productid from the datakeys collection
 int productid = convert.toint32(datalist1.datakeys[e.item.itemindex]);
 // read in the product name and price values
 textbox productname = (textbox)e.item.findcontrol("productname");
 textbox unitprice = (textbox)e.item.findcontrol("unitprice");
 string productnamevalue = null;
 if (productname.text.trim().length > 0)
 productnamevalue = productname.text.trim();
 decimal? unitpricevalue = null;
 if (unitprice.text.trim().length > 0)
 unitpricevalue = decimal.parse(unitprice.text.trim(),
  system.globalization.numberstyles.currency);
 // call the productsbll's updateproduct method...
 productsbll productsapi = new productsbll();
 productsapi.updateproduct(productnamevalue, unitpricevalue, productid);
 // revert the datalist back to its pre-editing state
 datalist1.edititemindex = -1;
 datalist1.databind();
}

  首先从datakeys集合里读出product的productid。然后将两个textbox的text属性存起来。我们用decimal.parse() 方法去读unitprice textbox的值,以便在这个值有货币符号时可以正确的转换。

  注意:只有在textbox的text指定了值的情况下,productnamevalue和unitpricevalue变量才会被赋值。否则,会在更新数据时使用一个null值。也就是说我们的代码会将空字符串转换为null值,而在gridview,detailsview和formview控件的编辑界面里null是缺省值。获取值后,调用productsbll类的updateproduct方法,将product的name,price和productid传进去。使用和cancelcommand event handler里同样的逻辑返回到datalist编辑前状态。完成了editcommand,cancelcommand和updatecommand event handler后,用户可以编辑product的name和price了。见图14。

http://www.lhsxpumps.com/_images/10qianwan/20171212/b_1_201712121909254339.jpg
图 14: 浏览页时所有的products都是只读模式

http://www.lhsxpumps.com/_images/10qianwan/20171212/b_1_201712121909258853.jpg
图 15: 点击edit button

http://www.lhsxpumps.com/_images/10qianwan/20171212/b_1_201712121909253681.jpg
图 16: 改变值后,点击 update返回只读模式

第七步: 增加删除功能

增加删除功能的步骤和增加编辑功能差不多。简单来说我们需要在itemtemplate里添加一个delete button,当点击时:

从datakeys 集合里读取关联的proudct的productid .
调用productsbll class的deleteproduct 方法执行删除操作.
重新绑定数据到 datalist.
首先来增加一个delete button.

  当点击一个commandname为“edit”, “update”, 或“cancel”的button时,会激发datalist的itemcommand事件和另外一个事件(比如,使用“edit”时editcommand 事件会被激发)。同样的,commandname为“delete”时会激发deletecommand 事件(和itemcommand一起)。

在edit button后面增加一个delete button ,将commandname属性设为“delete”. 完成后声明代码如下:

<itemtemplate>
 <h5>
 <asp:label runat="server" id="productnamelabel"
  text='<%# eval("productname") %>' />
 </h5>
 price: <asp:label runat="server" id="label1"
  text='<%# eval("unitprice", "{0:c}") %>' />
 <br />
 <asp:button runat="server" id="editproduct" commandname="edit"
 text="edit" />
 
 <asp:button runat="server" id="deleteproduct" commandname="delete"
 text="delete" />
 <br />
 <br />
</itemtemplate>

然后为datalist的deletecommand事件创建一个event handler,见下面的代码:

protected void datalist1_deletecommand(object source, datalistcommandeventargs e)
{
 // read in the productid from the datakeys collection
 int productid = convert.toint32(datalist1.datakeys[e.item.itemindex]);
 // delete the data
 productsbll productsapi = new productsbll();
 productsapi.deleteproduct(productid);
 // rebind the data to the datalist
 datalist1.databind();
}
        

  点击delete button 会引起postback,并激发datalist的deletecommand事件。在事件处理中,被点击的product的productid的值通过datekeys集合来获取。然后,调用productsbll类的deleteproduct方法来删除product。删除product后,要将数据重新绑定到datalist(datalist1.databind()),否则datalist里还会看到刚才删除的product。

总结

  通过少量的代码,datalist也可以拥有gridview的编辑删除功能。在本章我们学习了如何创建一个两列的显示product的页,并且可以编辑name和price,删除product。增加编辑和删除功能需要在itemtemplate和edititemtemplate里增加合适的控件,创建对应的事件处理,读取用户的输入和主键值,然后调用bll。

  虽然我们为datalist增加了基本的编辑和删除功能,它还是缺少一些高级特性。比如,没有输入字段验证- 如果用户输入的price太“贵”,decimal.parse在转换为decimal时会抛出异常。同样的,如果在更新数据时,bll或dal里有异常,用户会看到系统错误。在删除时没有任何确认,很可能会误删数据。在后面的教程里我们会学习如何改善这些问题。

  祝编程快乐!

作者简介

  本系列教程作者 scott mitchell,著有六本asp/asp.net方面的书,是4guysfromrolla.com的创始人,自1998年以来一直应用 微软web技术。大家可以点击查看全部教程《[翻译]scott mitchell 的asp.net 2.0数据教程》,希望对大家的学习asp.net有所帮助。

如对本文有疑问,请在下面进行留言讨论,广大热心网友会与你互动!! 点击进行留言回复

相关文章:

验证码:
移动技术网