当前位置: 移动技术网 > IT编程>开发语言>.net > 在ASP.NET 2.0中操作数据之五十一:从GridView的页脚插入新记录

在ASP.NET 2.0中操作数据之五十一:从GridView的页脚插入新记录

2017年12月12日  | 移动技术网IT编程  | 我要评论
导言:   正如教程《》里探讨过的一样, gridview, detailsview和formview web控件都有内置的修改数据的功能。当声明绑定到数据源控件时,可以

导言:

  正如教程《》里探讨过的一样, gridview, detailsview和formview web控件都有内置的修改数据的功能。当声明绑定到数据源控件时,可以快速而方便地修改数据——甚至不用写一行代码。不幸的是,只有detailsview和formview控件提供了内置的插入、编辑、删除功能,而 gridview控件只支持编辑、删除功能。不过,稍许努力,我们就能使gridview控件包含一个插入界面。

  为了给gridview添加插入功能,我们要决定如何添加新记录:创建插入界面,编码插入数据。在本教程,我们将为gridview的页脚行(footer row )添加插入界面(见图1)。其中每一列包含相应的用户界面元件(比如在textbox里输入产品名称,在dropdownlis里选择供应商等等),同时我们需要一个"add"按钮,当点击时,发生页面回传,将新记录添加到表products里。

http://www.lhsxpumps.com/_images/10qianwan/20171212/b_1_201712121908495197.jpg
图1:页脚行提供了一个添加新记录的界面

第一步:在gridview控件里展示产品信息

  首先添加一个展示产品的gridview控件。打开enhancedgridview文件夹里的insertthroughfooter.aspx页面,在上面添加一个gridview控件,设其id为products,然后,在其智能标签里绑定到一个名为productsdatasource的objectdatasource 。

//img.jbzj.com/file_images/article/201605/2016051610461540.gif
图2:创建一个名为productsdatasource的新objectdatasource

  设置该objectdatasource调用productsbll类的getproducts()方法获取产品信息。在本教程里,我们只关注于添加插入功能,与编辑和删除无关。所以,确保在“插入”选项卡里选addproduct()方法。而在“编辑”和“删除”里选“(none)”。

//img.jbzj.com/file_images/article/201605/2016051610461541.gif
图3:将 objectdatasource的insert()方法设置为addproduct()

//img.jbzj.com/file_images/article/201605/2016051610461642.gif
图4:在update和delete选项里选“(none)”

  完成设置后,visual studio会自动添加相关列。现在,我们暂时不管这些列,在教程后续部分,我们将移除一些列,因为在添加新记录时我们不需指定这些列的值。

  因为数据库中大概有80个产品,所以我们最好还是启用分页功能,以便使插入界面更直观、更易操作。回到页面,在gridview的智能标签里启用分页。

现在,gridview和objectdatasource的声明代码看起来和下面的差不多:

<asp:gridview id="products" runat="server" autogeneratecolumns="false"
 datakeynames="productid" datasourceid="productsdatasource"
 allowpaging="true" enableviewstate="false">
 <columns>
 <asp:boundfield datafield="productid" headertext="productid"
  insertvisible="false" readonly="true"
  sortexpression="productid" />
 <asp:boundfield datafield="productname" headertext="productname"
  sortexpression="productname" />
 <asp:boundfield datafield="supplierid" headertext="supplierid"
  sortexpression="supplierid" />
 <asp:boundfield datafield="categoryid" headertext="categoryid"
  sortexpression="categoryid" />
 <asp:boundfield datafield="quantityperunit" headertext="quantityperunit"
  sortexpression="quantityperunit" />
 <asp:boundfield datafield="unitprice" headertext="unitprice"
  sortexpression="unitprice" />
 <asp:boundfield datafield="unitsinstock" headertext="unitsinstock"
  sortexpression="unitsinstock" />
 <asp:boundfield datafield="unitsonorder" headertext="unitsonorder"
  sortexpression="unitsonorder" />
 <asp:boundfield datafield="reorderlevel" headertext="reorderlevel"
  sortexpression="reorderlevel" />
 <asp:checkboxfield datafield="discontinued" headertext="discontinued"
  sortexpression="discontinued" />
 <asp:boundfield datafield="categoryname" headertext="categoryname"
  readonly="true" sortexpression="categoryname" />
 <asp:boundfield datafield="suppliername" headertext="suppliername"
  readonly="true" sortexpression="suppliername" />
 </columns>
</asp:gridview>

<asp:objectdatasource id="productsdatasource" runat="server"
 insertmethod="addproduct" oldvaluesparameterformatstring="original_{0}"
 selectmethod="getproducts" typename="productsbll">
 <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>


//img.jbzj.com/file_images/article/201605/2016051610461643.gif
图5:在一个启用了分页功能的gridview里,显示产品的所有数据项

第2步:添加一个页脚行

  gridview控件包含页眉行、数据行和页脚行。gridview控件showheader和showfooter属性决定了是否显示页眉行和页脚行。如果要显示页脚行,我们需要将 showfooter属性设置为true。如图6所示:

//img.jbzj.com/file_images/article/201605/2016051610461644.gif
图6:设showfooter属性为true,添加页脚行

  我们注意到页脚行的背景色是深红色,这是由于我们在教程《使用objectdatasource展现数据》里创建了一个名为datawebcontrols的主题,并将其应用为所有的页面底色。特别的,皮肤文件gridview.skin设置footerstyle属性使用footerstyle css ,其代码如下:

.footerstyle
{
 background-color: #a33;
 color: white;
 text-align: right;
}

  注意:在以前的教程我们提到过使用gridview的页脚行。如果不清楚的话,请查阅教程第15章《在gridview的页脚中显示统计信息

  设置showfooter属性为true后,在浏览器里观看效果。当前的页脚行并不包含任何的文字或web控件。在第3步,我们将修改其包含相应的插入界面。

//img.jbzj.com/file_images/article/201605/2016051610461745.gif
图7:页脚行显示为空白

第3步:自定义页脚行

  回顾教程《在gridview控件中使用templatefield》,在那篇教程我们探讨了如何对gridview的某一列使用templatefields(而不是boundfields或checkboxfields) ,从而实现自定义显示样式;而在教程《》里我们看到如何在gridview里使用templatefields定制编辑界面。一个templatefield是由诸如itemtemplate、edititemtemplate等模板构成的。比如,itemtemplate模板显示的数据行为只读状态;而edititemtemplate模板定制了一个编辑行界面。

  除了itemtemplate、edititemtemplate等模板外,templatefield也包含一个名为footertemplate的模板,它为容器指定页脚行。所以我们可以在footertemplate模板里添加插入界面要用到的web控件。让我们开始吧,首先,我们将gridview控件里的所有列转换成templatefields。在gridview控件的智能标签里点击“编辑列”,在左边选中每个域,再点击“convert this field into a templatefield” 。

//img.jbzj.com/file_images/article/201605/2016051610461746.gif
图8:将每个域转换为一个templatefield

  点击“convert this field into a templatefield”的话,将当前类型的域转换成相应的templatefield。比如,每个boundfield将转换成这样的templatefield,它的itemtemplate包含一个label控件来显示相应的数据域;它的edititemtemplate使用一个textbox控件来显示相应的数据域。例如,在这里,名为productname的boundfield将被转换为如下所示的templatefield :

<asp:templatefield headertext="productname" sortexpression="productname">
 <edititemtemplate>
 <asp:textbox id="textbox1" runat="server"
  text='<%# bind("productname") %>'></asp:textbox>
 </edititemtemplate>
 <itemtemplate>
 <asp:label id="label2" runat="server"
  text='<%# bind("productname") %>'></asp:label>
 </itemtemplate>
</asp:templatefield>

  同样的,名为discontinued的checkboxfield转换为templatefield后,其itemtemplate 和 edititemtemplate 模板都将包含一个checkbox web控件(只是itemtemplate模板里的checkbox不可用);而处于“只读”状态的productid boundfield转换成templatefield后,其itemtemplate 和 edititemtemplate 模板都包含一个label控件。简而言之,将gridview里的某一列转换为一个 templatefield,是定制自定义模板的一种又快又容易的方法,且不会丧失该列应有的功能。

  由于我们不需要gridview支持编辑功能,将每个templatefield的edititemtemplate模板删除,只留下itemtemplate模板。完成后, gridview的代码看起来应和下面的差不多:

<asp:gridview id="products" runat="server" autogeneratecolumns="false"
 datakeynames="productid" datasourceid="productsdatasource"
 allowpaging="true" enableviewstate="false" showfooter="true">
 <columns>
 <asp:templatefield headertext="productid" insertvisible="false"
  sortexpression="productid">
  <itemtemplate>
  <asp:label id="label1" runat="server"
   text='<%# bind("productid") %>'></asp:label>
  </itemtemplate>
 </asp:templatefield>
 <asp:templatefield headertext="productname" sortexpression="productname">
  <itemtemplate>
  <asp:label id="label2" runat="server"
   text='<%# bind("productname") %>'></asp:label>
  </itemtemplate>
 </asp:templatefield>
 <asp:templatefield headertext="supplierid" sortexpression="supplierid">
  <itemtemplate>
  <asp:label id="label3" runat="server"
   text='<%# bind("supplierid") %>'></asp:label>
  </itemtemplate>
 </asp:templatefield>
 <asp:templatefield headertext="categoryid" sortexpression="categoryid">
  <itemtemplate>
  <asp:label id="label4" runat="server"
   text='<%# bind("categoryid") %>'></asp:label>
  </itemtemplate>
 </asp:templatefield>
 <asp:templatefield headertext="quantityperunit"
  sortexpression="quantityperunit">
  <itemtemplate>
  <asp:label id="label5" runat="server"
   text='<%# bind("quantityperunit") %>'></asp:label>
  </itemtemplate>
 </asp:templatefield>
 <asp:templatefield headertext="unitprice" sortexpression="unitprice">
  <itemtemplate>
  <asp:label id="label6" runat="server"
   text='<%# bind("unitprice") %>'></asp:label>
  </itemtemplate>
 </asp:templatefield>
 <asp:templatefield headertext="unitsinstock"
  sortexpression="unitsinstock">
  <itemtemplate>
  <asp:label id="label7" runat="server"
   text='<%# bind("unitsinstock") %>'></asp:label>
  </itemtemplate>
 </asp:templatefield>
 <asp:templatefield headertext="unitsonorder"
  sortexpression="unitsonorder">
  <itemtemplate>
  <asp:label id="label8" runat="server"
   text='<%# bind("unitsonorder") %>'></asp:label>
  </itemtemplate>
 </asp:templatefield>
 <asp:templatefield headertext="reorderlevel"
  sortexpression="reorderlevel">
  <itemtemplate>
  <asp:label id="label9" runat="server"
   text='<%# bind("reorderlevel") %>'></asp:label>
  </itemtemplate>
 </asp:templatefield>
 <asp:templatefield headertext="discontinued"
  sortexpression="discontinued">
  <itemtemplate>
  <asp:checkbox id="checkbox1" runat="server"
   checked='<%# bind("discontinued") %>' enabled="false" />
  </itemtemplate>
 </asp:templatefield>
 <asp:templatefield headertext="categoryname"
  sortexpression="categoryname">
  <itemtemplate>
  <asp:label id="label10" runat="server"
   text='<%# bind("categoryname") %>'></asp:label>
  </itemtemplate>
 </asp:templatefield>
 <asp:templatefield headertext="suppliername"
  sortexpression="suppliername">
  <itemtemplate>
  <asp:label id="label11" runat="server"
   text='<%# bind("suppliername") %>'></asp:label>
  </itemtemplate>
 </asp:templatefield>
 </columns>
</asp:gridview>

  现在, 每个gridview列都已经转换成一个templatefield,我们在其footertemplate里添加适当的插入界面。然而,有些列没有插入界面(比如productid),其它列的templatefield模板将包含web控件,供用户输入产品信息。

  在gridview的智能标签里点击“edit templates”,从下拉列表里选择某列的 footertemplate模板,从工具箱里拖一个适当的控件到页面上。

//img.jbzj.com/file_images/article/201605/2016051610461747.gif
图9:在每列的footertemplate里添加适当的插入界面。

下面列出了gridview的所有列,并指定每列添加哪些插入界面:

productid – 无
productname –添加一个textbox,id为newproductname;再添加一个
requiredfieldvalidator控件,防止用户未输入产品名。
supplierid –无
categoryid – 无
quantityperunit – 添加一个textbox,id为newquantityperunit
unitprice – 添加一个textbox,id为newunitprice,再添加一个comparevalidator控件,确保用户输入的是货币值,且>=0
unitsinstock –添加一个textbox,id为newunitsinstock,再添加一个comparevalidator控件,确保用户输入的是整数值,且>=0
unitsonorder – 添加一个textbox,id为newunitsonorder,再添加一个comparevalidator控件,确保用户输入的是整数值,且>=0
reorderlevel –添加一个textbox,id为newreorderlevel,再添加一个comparevalidator控件,确保用户输入的是整数值,且>=0
discontinued–添加一个checkbox,id为newdiscontinued
categoryname ––添加一个dropdownlist控件,id为newcategoryid。将其绑定到一个名为categoriesdatasource的objectdatasource控件,设置它调用categoriesbll类的getcategories() 方法。设置dropdownlist控件显示categoryname,并将dropdownlist控件的values设置为categoryid
suppliername –添加一个dropdownlist控件,id为newsupplierid.将其绑定到一个名为suppliersdatasource的objectdatasource控件,设置它调用suppliersbll类的getsuppliers()方法.设置dropdownlist控件显示companyname ,并将dropdownlist控件的values设置为supplierid.

  将每个validation控件的forecolor属性清空,以便用在footerstyle css类定义的白色背景色取代默认的红色;同时将errormessage设置为详细的错误提示;将text属性设置为星号。在每个footertemplates里,只要包含有validation控件,将其wrap属性设置为false。最后,在gridview控件下面添加一个validationsummary 控件,设showmessagebox属性为true;showsummary属性为false。

  当添加一个新产品时,我们需要给出categoryid和supplierid值。页面上的2个dropdownlist控件显示的是categoryname 和suppliername,但传递的是我们需要的
categoryid和supplierid值。为什么不直接显示categoryid和supplierid值呢?因为最终用户对categoryname 和suppliername更感兴趣。既然现在可以在显示categoryname 和suppliername的插入界面获取对应的categoryid和supplierid值,我们将categoryid 和supplierid 2个templatefields从gridview移除。

  同样,当添加新产品时我们不需要productid,那么我们也可以删除productid templatefield,不过,在这里我们保留它。除了textboxes,dropdownlists、
checkboxes以及validation控件外,我们还需要在插入界面添加一个“add”按钮。当点击该按钮时,将新记录添加到数据库。在第4步,我们将在productid templatefield的footertemplate模板添加一个“add”按钮。

  按你喜欢的方式改进外观。比如,将unitprice值格式化为货币形式;将unitsinstock, unitsonorder和reorderlevel三列放在右边;修改templatefields的headertext属性等。

  在footertemplates里完成插入界面的修改后,移除supplierid 和 categoryid templatefields,最终,你的gridview控件的声明代码看起来应该和下面的差不多:

<asp:gridview id="products" runat="server" autogeneratecolumns="false"
 datakeynames="productid" datasourceid="productsdatasource"
 allowpaging="true" enableviewstate="false" showfooter="true">
 <columns>
 <asp:templatefield headertext="productid" insertvisible="false"
  sortexpression="productid">
  <itemtemplate>
  <asp:label id="label1" runat="server"
   text='<%# bind("productid") %>'></asp:label>
  </itemtemplate>
  <itemstyle horizontalalign="center" />
 </asp:templatefield>
 <asp:templatefield headertext="product" sortexpression="productname">
  <itemtemplate>
  <asp:label id="label2" runat="server"
   text='<%# bind("productname") %>'></asp:label>
  </itemtemplate>
  <footertemplate>
  <asp:textbox id="newproductname" runat="server"></asp:textbox>
  <asp:requiredfieldvalidator id="requiredfieldvalidator1"
   runat="server" controltovalidate="newproductname"
   display="dynamic" forecolor=""
   errormessage="you must enter a name for the new product.">
   * </asp:requiredfieldvalidator>
  </footertemplate>
  <footerstyle wrap="false" />
 </asp:templatefield>
 <asp:templatefield headertext="category" sortexpression="categoryname">
  <itemtemplate>
  <asp:label id="label10" runat="server"
   text='<%# bind("categoryname") %>'></asp:label>
  </itemtemplate>
  <footertemplate>
  <asp:dropdownlist id="newcategoryid" runat="server"
   datasourceid="categoriesdatasource"
   datatextfield="categoryname" datavaluefield="categoryid">
  </asp:dropdownlist>
  <asp:objectdatasource id="categoriesdatasource" runat="server"
   oldvaluesparameterformatstring="original_{0}"
   selectmethod="getcategories" typename="categoriesbll">
  </asp:objectdatasource>
  </footertemplate>
 </asp:templatefield>
 <asp:templatefield headertext="supplier" sortexpression="suppliername">
  <itemtemplate>
  <asp:label id="label11" runat="server"
   text='<%# bind("suppliername") %>'></asp:label>
  </itemtemplate>
  <footertemplate>
  <asp:dropdownlist id="newsupplierid" runat="server"
   datasourceid="suppliersdatasource"
   datatextfield="companyname" datavaluefield="supplierid">
  </asp:dropdownlist><asp:objectdatasource id="suppliersdatasource"
   runat="server" oldvaluesparameterformatstring="original_{0}"
   selectmethod="getsuppliers" typename="suppliersbll">
  </asp:objectdatasource>
  </footertemplate>
 </asp:templatefield>
 <asp:templatefield headertext="qty/unit" sortexpression="quantityperunit">
  <itemtemplate>
  <asp:label id="label5" runat="server"
   text='<%# bind("quantityperunit") %>'></asp:label>
  </itemtemplate>
  <footertemplate>
  <asp:textbox id="newquantityperunit" runat="server"></asp:textbox>
  </footertemplate>
 </asp:templatefield>
 <asp:templatefield headertext="price" sortexpression="unitprice">
  <itemtemplate>
  <asp:label id="label6" runat="server"
   text='<%# bind("unitprice", "{0:c}") %>'></asp:label>
  </itemtemplate>
  <footertemplate>
  $<asp:textbox id="newunitprice" runat="server" columns="8" />
  <asp:comparevalidator id="comparevalidator1" runat="server"
   controltovalidate="newunitprice"
   errormessage="you must enter a valid currency value greater than
   or equal to 0.00. do not include the currency symbol."
   forecolor="" operator="greaterthanequal" type="currency"
   valuetocompare="0" display="dynamic">
   * </asp:comparevalidator>
  </footertemplate>
  <itemstyle horizontalalign="right" />
  <footerstyle wrap="false" />
 </asp:templatefield>
 <asp:templatefield headertext="units in stock"
  sortexpression="units in stock">
  <itemtemplate>
  <asp:label id="label7" runat="server"
   text='<%# bind("unitsinstock") %>'></asp:label>
  </itemtemplate>
  <footertemplate>
  <asp:textbox id="newunitsinstock" runat="server" columns="5" />
  <asp:comparevalidator id="comparevalidator2" runat="server"
   controltovalidate="newunitsinstock" display="dynamic"
   errormessage="you must enter a valid numeric value for units
   in stock that's greater than or equal to zero."
   forecolor="" operator="greaterthanequal" type="integer"
   valuetocompare="0">*</asp:comparevalidator>
  </footertemplate>
  <itemstyle horizontalalign="right" />
  <footerstyle wrap="false" />
 </asp:templatefield>
 <asp:templatefield headertext="units on order" sortexpression="unitsonorder">
  <itemtemplate>
  <asp:label id="label8" runat="server"
   text='<%# bind("unitsonorder") %>'></asp:label>
  </itemtemplate>
  <footertemplate>
  <asp:textbox id="newunitsonorder" runat="server" columns="5" />
  <asp:comparevalidator id="comparevalidator3" runat="server"
   controltovalidate="newunitsonorder" display="dynamic"
   errormessage="you must enter a valid numeric value for units on
   order that's greater than or equal to zero."
   forecolor="" operator="greaterthanequal" type="integer"
   valuetocompare="0">*</asp:comparevalidator>
  </footertemplate>
  <itemstyle horizontalalign="right" />
  <footerstyle wrap="false" />
 </asp:templatefield>
 <asp:templatefield headertext="reorder level" sortexpression="reorderlevel">
  <itemtemplate>
  <asp:label id="label9" runat="server"
   text='<%# bind("reorderlevel") %>'></asp:label>
  </itemtemplate>
  <footertemplate>
  <asp:textbox id="newreorderlevel" runat="server" columns="5" />
  <asp:comparevalidator id="comparevalidator4" runat="server"
   controltovalidate="newreorderlevel" display="dynamic"
   errormessage="you must enter a valid numeric value for reorder
   level that's greater than or equal to zero."
   forecolor="" operator="greaterthanequal" type="integer"
   valuetocompare="0">*</asp:comparevalidator>
  </footertemplate>
  <itemstyle horizontalalign="right" />
  <footerstyle wrap="false" />
 </asp:templatefield>
 <asp:templatefield headertext="discontinued" sortexpression="discontinued">
  <itemtemplate>
  <asp:checkbox id="checkbox1" runat="server"
   checked='<%# bind("discontinued") %>' enabled="false" />
  </itemtemplate>
  <footertemplate>
  <asp:checkbox id="newdiscontinued" runat="server" />
  </footertemplate>
  <itemstyle horizontalalign="center" />
  <footerstyle horizontalalign="center" />
 </asp:templatefield>
 </columns>
</asp:gridview>

  在浏览器里查看该页面时,gridview控件的页脚行显示为一个比较完善的插入界面(如图10所示)。此时,插入界面并不包含一种方法将输入的数据添加进数据库。并将我们也没有阐述那些键入的数据是如何转换成一条记录的。在第4步,我们将看到如何添加一个“add ”按钮,在页面回传后如何执行代码。在第5步,我们看如何将键入的数据转换成一条记录添加到数据库。

//img.jbzj.com/file_images/article/201605/2016051610462748.gif
图10:gridview的页脚行提供了添加新记录的界面

第4步:在插入界面添加add按钮

  如前所述我们需要在界面添加一个add按钮,我们可以在某个footertemplate里或另外增加一列来放置该按钮来达到这个目的。在本教程,我们在productid templatefield的footertemplate里添加该按钮。

  点击gridview的智能标签中的“编辑模板”,选择productid对应的 footertemplate ,添加一个button web控件(linkbutton 或是imagebutton,只要你喜欢), 设id为addproduct;commandname属性为insert;text属性为“add”,如图11所示:

//img.jbzj.com/file_images/article/201605/2016051610462749.gif
图11:将add button放在productid templatefield的footertemplate模板

  添加按钮后,在浏览器查看该页面。如果我们在界面输入无效的数据,再点add按钮时,页面回转中断,同时validationsummary控件详细的列出了那些无效数据(如图12)。当输入适当的数据后,再点按钮,将引发页面回传,但是没有记录添加到数据库里。我们需要编写代码实现插入数据的功能。

http://www.lhsxpumps.com/_images/10qianwan/20171212/b_1_201712121908517356.jpg
图12:如果输入的是无效数据,将会使页面回转中断

注意:界面里的validation控件未被设置为一组,当页面中只有插入界面包含validation控件的话,运行没问题。但是,如果在页面中还有其它的validation控件的话(比如,如果还存在一个编辑界面,其中也包含validation控件),我们应该将插入界面里的validation控件和add按钮的validationgroup属性设置为同一个值,使其为一个特定的确认组。

第5步:向表products添加一条新记录

  当使用gridview控件的内置的编辑功能时,gridview会自动的处理编辑产品所必要的工作。当点击编辑按钮时,它把在编辑页面键入的数据拷贝到objectdatasource的updateparameters参数集包含的参数,再调用objectdatasource控件的update()方法执行更新。由于gridview没有提供内置的功能供插入数据,我们必须编写代码调用objectdatasource控件的insert()方法,将在插入界面键入的数据复制到 objectdatasource控件的insertparameters集合里。

  就像在教程28章《gridview里的button》里探讨的一样,任何时候,只要点击 gridview控件里的button, linkbutton或imagebutton,发生页面回转时引发gridview的rowcommand事件。不管这些button, linkbutton、imagebutton控件是显式添加的(比如,在页脚行添加的add按钮),或者是gridview控件自动添加的(比如启用分页功能或排序功能时,顶部的出现的那些linkbutton)。

  为相应用户点击add按钮,我们要为gridview的rowcommand事件创建一个事件处理器。由于任何时候点击gridview控件的任何button, linkbutton或imagebutton都会触发该事件,我们必须指定当传入事件处理器的commandname属性值与add按钮的一致时(即:“insert”),并且键入的数据无误时,才执行插入操作。代码如下:

protected void products_rowcommand(object sender, gridviewcommandeventargs e)
{
 // insert data if the commandname == "insert"
 // and the validation controls indicate valid data...
 if (e.commandname == "insert" && page.isvalid)
 {
 // todo: insert new record...
 }
}

  注意:你可能会很奇怪为什么还要检查page.isvalid属性呢?毕竟,如果在插入界面输入了无效的数据时,页面回传会中断。检查page.isvalid属性是为了防止用户未启用javascript或巧妙的绕过客户端验证的情况。简而言之,如果没有进行客户端进行有效性验证的话,在处理数据以前必须在服务器端再进行一次有效性验证。

  在第1步,objectdatasource控件productsdatasource的insert()方法映射的是productsbll类的addproduct方法。为了在表products里添加新记录,我们只需要简单的调用objectdatasource的insert()方法:

protected void products_rowcommand(object sender, gridviewcommandeventargs e)
{
 // insert data if the commandname == "insert"
 // and the validation controls indicate valid data...
 if (e.commandname == "insert" && page.isvalid)
 {
 // insert new record
 productsdatasource.insert();
 }
}

  现在可以调用insert()方法,剩下的步骤是把在插入界面键入的值传递给productsbll类的addproduct方法中的参数。就像在教程17章《》探讨的一样,可以通过objectdatasource控件的inserting事件来实现。在inserting事件里,我们需要编程访问页脚行里的控件,将其值赋给e.inputparameters集合。当用户忽略了某个值时——比如使reorderlevel文本框为空,我们应该指定该值为null。因为addproducts方法允许那些nullable类型的列接收null值。代码如下:

protected void productsdatasource_inserting
 (object sender, objectdatasourcemethodeventargs e)
{
 // programmatically reference web controls in the inserting interface...
 textbox newproductname =
 (textbox)products.footerrow.findcontrol("newproductname");
 dropdownlist newcategoryid =
 (dropdownlist)products.footerrow.findcontrol("newcategoryid");
 dropdownlist newsupplierid =
 (dropdownlist)products.footerrow.findcontrol("newsupplierid");
 textbox newquantityperunit =
 (textbox)products.footerrow.findcontrol("newquantityperunit");
 textbox newunitprice =
 (textbox)products.footerrow.findcontrol("newunitprice");
 textbox newunitsinstock =
 (textbox)products.footerrow.findcontrol("newunitsinstock");
 textbox newunitsonorder =
 (textbox)products.footerrow.findcontrol("newunitsonorder");
 textbox newreorderlevel =
 (textbox)products.footerrow.findcontrol("newreorderlevel");
 checkbox newdiscontinued =
 (checkbox)products.footerrow.findcontrol("newdiscontinued");

 // set the objectdatasource's insertparameters values...
 e.inputparameters["productname"] = newproductname.text;
 
 e.inputparameters["supplierid"] =
 convert.toint32(newsupplierid.selectedvalue);
 e.inputparameters["categoryid"] =
 convert.toint32(newcategoryid.selectedvalue);
 
 string quantityperunit = null;
 if (!string.isnullorempty(newquantityperunit.text))
 quantityperunit = newquantityperunit.text;
 e.inputparameters["quantityperunit"] = quantityperunit;

 decimal? unitprice = null;
 if (!string.isnullorempty(newunitprice.text))
 unitprice = convert.todecimal(newunitprice.text);
 e.inputparameters["unitprice"] = unitprice;

 short? unitsinstock = null;
 if (!string.isnullorempty(newunitsinstock.text))
 unitsinstock = convert.toint16(newunitsinstock.text);
 e.inputparameters["unitsinstock"] = unitsinstock;

 short? unitsonorder = null;
 if (!string.isnullorempty(newunitsonorder.text))
 unitsonorder = convert.toint16(newunitsonorder.text);
 e.inputparameters["unitsonorder"] = unitsonorder;

 short? reorderlevel = null;
 if (!string.isnullorempty(newreorderlevel.text))
 reorderlevel = convert.toint16(newreorderlevel.text);
 e.inputparameters["reorderlevel"] = reorderlevel;
 
 e.inputparameters["discontinued"] = newdiscontinued.checked;
}

添加完inserting事件处理器后,我们就可以通过gridview控件的页脚行添加记录了。开始吧,尝试添加几个产品。

优化并自定义add操作

  一般来说,点击add按钮后,就将为数据库添加一个新记录。但是没有任何直观的提示反映成功地添加了记录。的确,应该用一个label web控件或客户端的消息框提示用户已经成功地添加了产品,我把它作为一个练习留给读者。

  本文使用的gridview控件没有对所显示的产品进行任何排序,也未允许最终用户对数据排序。因此,产品依它们在数据库中的次序排序——依主键值顺序。由于每条新添加的记录的productid值比上一条的值大,所以,当添加新记录时,它就自然地排到最后一位了。因此,当添加新记录时,你希望自动地转到gridview控件的最后一页。怎么才能办到呢?在rowcommand事件处理器里,调用productsdatasource.insert()方法后,紧接着添加如下一行代码,它说明当数据绑定到gridview后将转到最后一页:

// indicate that the user needs to be sent to the last page
sendusertolastpage = true;

  其中sendusertolastpage是页面层(page-level)的布尔变量,其初始值为false。在gridview控件的databound事件处理器中,如果sendusertolastpage为false(译注:应该是true),pageindex属性将使用户转到最后一页。

protected void products_databound(object sender, eventargs e)
{
 // send user to last page of data, if needed
 if (sendusertolastpage)
 products.pageindex = products.pagecount - 1;
}

  为什么我们要在databound事件处理器(而不是在rowcommand事件处理器)里设置pageindex属性呢?如果在rowcommand里设置pageindex属性的话,它返回的是在添加新记录之前的pageindex值。在大多数情况下,这样做是没有问题的,但是,如果新添加的记录刚好落到新的一页(译注:比如原本有80个产品,分为8页显示,此时末页的pageindex为7,当添加第81条记录时,新添加的产品变成第9页第1条记录了,此时末页的pageindex为8,而不是添加产品前的7),而我们使用rowcommand里设置的pageindex值话,页面将跳往倒数第2页,而不是我们期望的末页。而databound事件是在添加产品且重新绑定以后才发生,我们在databound事件处理器里设置的pageindex值才是真正的末页的pageindex值。

  最后,本文用到的gridview看起来相当宽,因为添加产品信息要用到很多列。因此,最好将它设置为竖向排列。另外我们可以减少输入列来缩小整体宽度,也许我们添加新产品时用不到unitsonorder、unitsinstock、reorderlevel这几项,那么在gridview里将其移除即可。

删除unitsonorder、unitsinstock、reorderlevel列后需要做调整,有2种方法:

1.仍然使用addproduct方法,不过其需要传入unitsonorder、unitsinstock、reorderlevel列的值。我们可以在inserting事件处理器中,对上述3列使用“硬编码”值或默认值。
2.在productsbll类里对addproduct方法重载,使其不需要传入unitsonorder、unitsinstock、reorderlevel列的值。然后,在asp.net page页面设置objectdatasource使用重载的addproduct方法。

以上2种方法都能奏效。在以前的教程里我们使用的是后者,对productsbll类的updateproduct方法多次重载。

总结:

  detailsview和formview控件拥有内置的inserting插入数据功能,而gridview没有。不过我们可以使用gridview控件的页脚行来达到此目的。要显示页脚行只需要设置showfooter属性为true。我们可以这样对页脚行进行用户定制:将每一列转换成templatefield,并在其footertemplate模板定制插入界面。正如我们在本章看到的那样,footertemplate 模板可以包含buttons,textboxes, dropdownlists,checkboxes, data source controls,validation controls等控件,除此以外,为了便于用户输入,add按钮, linkbutton或imagebutton等也是必需的。

  当点击add按钮后,将调用objectdatasource控件的insert()方法,进而使用其映射的插入数据方法(具体到本文,即为productsbll类的addproduct方法),在调用具体的插入数据方法前,我们需要将插入界面里键入的数据传递objectdatasource控件的insertparameters集合。要达到该目的,我们应该在objectdatasource控件的inserting事件处理器里,编程访问插入界面的web控件。

  本教程探讨了优化gridview外观的技巧。接下来的一系列教程,我们看如何使用2进制数据——比如images, pdfs, word documents等等,当然还有data web控件。

  祝编程快乐!

作者简介

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

如您对本文有疑问或者有任何想说的,请点击进行留言回复,万千网友为您解惑!

相关文章:

验证码:
移动技术网