我们基于ASP.NET 2.0构建了一个简化的在线购物车和PayPal系统;并通过这个示例,对ASP.NET 2.0中新引入的GridView控件作了深入研究
四. 构建数据
<asp:GridView id="gvBasket" AutoGenerateColumns="false" ShowHeader="True" ShowFooter="True" DataKeyNames="id" OnRowDataBound="gvBasket_RowDataBound" runat="server"> <Columns> <asp:ImageField DataImageurlField="thumb" alternatetext="Product Thumbnail" readonly="true" /> <asp:TemplateField HeaderText="Item"> <ItemTemplate> <h3><asp:Literal id="litItemName" runat="server" /></h3> </ItemTemplate> <FooterTemplate> <a href="delivery-costs.aspx" title="View the list of delivery charges">Delivery Charges</a> <br /><hr /> <b>Total</b> </FooterTemplate> </asp:TemplateField> </Columns> </asp:GridView> |
如果你仔细地观察一下这两个GridViews,你会注意到它们都把AutoGenerateColumns设置成false。如果没有这一行,或如果它被设置为true,那么,当我们绑定DataSource时,我们的列就会被创建。通过关闭这个特征,我们能够使用"Columns"子标签来定义自己的列。使用这一特征,我们能够创建许多不同类型的列。在这个演示程序中,我们使用了ImageField和TemplateField列类型。该ImageField列把一个图像路径作为它的值(通过DataImageUrlField属性),然后在它自己的列内显示该图像(当生成到该页面时)。
TemplateField是真正重要的列。它允许你定义一个HeaderTemplate,一个ItemTemplate和一个FooterTemplate。这三个标签允许你把任何内容放到这些地方。其中,HeaderTemplate和FooterTemplate都引用该列的页眉和页脚,而ItemTemplate引用body内容。
如果你观察一下购物篮GridView,你会看到我们已经使用ItemTemplate来显示购物篮中每一项的名字,价格和数量;然后,我们在FooterTemplate内显示运送费用及总价。上面的片断仅显示"name"列和它的页脚;完整的实现,请参考default.aspx源文件。因为每一列的页眉都是静态文本,所以我们使用HeaderTemplate跳过,并代之使用了TemplateField的HeaderText属性。为了观察一个GridView的页眉和页脚,你必须把GridView的ShowHeader和ShowFooter属性都设置为True。
使用ItemTemplate的另一个原因在于,你可以把其它HTML和.net标签放于其中。在这个演示程序中,存在若干不同的类型标签,包括<input>,<br/>,<hr/>,<asp:Literal>和<a>。把所有这些标签放到一个ItemTemplate标签内的唯一问题是,你必须多做一些工作来预填充它们,但是并不需要太多工作。第一步是设置GridView的RowDataBound事件。你可以指派一个函数给这个事件(在我们绑定DataSource后,在每次创建一行时,调用这个事件)。你可以在购物篮的GridView属性中看到这一点:
OnRowDataBound="gvBasket_RowDataBound"
相比之下,产品GridView相应的对应功能更简单些,但是它仅显示如何填充ItemTemplate而不是Header或Footer模板。
五. 一个重要的函数 现在,让我们看一下本示例程序中位于"cs"文件夹下的主要的类文件"site.aspx.cs",并且定位到一个称为gvBasket_RowDataBound的函数。下面是该函数的主要实现(当然,你可以参考下载源码检查该文件的其它部分):
protected void gvBasket_RowDataBound(object sender, GridViewRowEventArgs e) { switch( e.Row.RowType ) { case DataControlRowType.DataRow: //名称/描述 ((Literal)e.Row.FindControl("litItemName")).Text = Convert.ToString(((DataRowView)e.Row.DataItem)["name"]); //数量 string quantity = Convert.ToString(((DataRowView)e.Row.DataItem)["quantity"]); ((HtmlInputText)e.Row.FindControl("itProductQuantity")).Value = quantity; //价格 ((Literal)e.Row.FindControl("litPrice")).Text = String.Format("{0:C2}", Convert.ToDouble(((DataRowView)e.Row.DataItem)["price"]) * Convert.ToInt32(quantity)); break; case DataControlRowType.Footer: DataTable dtShop = getBasketDt(); double total = 0.00; for(int i = 0; i < dtShop.Rows.Count; i++) { total += Convert.ToInt32(dtShop.Rows[i]["quantity"]) * Convert.ToDouble(dtShop.Rows[i]["price"]); } ((Literal)e.Row.FindControl("litTotalQuantity")).Text = Convert.ToString(dtShop.Compute("SUM(quantity)", "")); ((Literal)e.Row.FindControl("litDeliveryPrice")).Text = String.Format("{0:C2}", Convert.ToDouble(calcDeliveryCost(total))); ((Literal)e.Row.FindControl("litTotalPrice")).Text = String.Format("{0:C2}", Convert.ToDouble(calcDeliveryCost(total)) + total); break; } } |
我们要做的第一件事是在RowType属性上执行一个切换,这样我们就能够区别我们在填充一个Header,Footer还是Item模板;因为所有这三个都是单独调用这同一个函数。对于产品和购物篮来说,我们都取得DataControlRowType.DataRow行类型,因为这是我们的ItemTemplate。
因为我们给HTML页面中的所有控件都确定了唯一的ID,所以我们能够使用行中的FindControl函数。这将返回一个"Object",如果该行中的任何控件有一个相匹配的ID话。我们可以把它强制转换成我们期望的对象类型,例如一个"Literal"或一个"HtmlInputText"域,然后经由它的TextorValue属性把数据指派给它。在每次绑定一个行时,它都被经由GridViewRowEventArgs.Row属性传递给该函数。使用这种技术,我们就能够存取该行的DataItem,它包含来自于DataSource的所有的行数据。然后,由我们来决定我们想从中提取哪些数据以及如何使用它。
在购物篮中,我们从DataItem中提取了名称,数量和价格三列数据,并且把它们指派给我们嵌入式在ItemTemplate中的相关控件。对于DataControlRowType.Footer,情况基本一致,除了我们从会话状态提取DataSource的一个副本之外(getBasketDt();),因为我们想使用所有行中的信息生成总值及运送费用,而不仅仅是传递到该函数中的单行数据。
六. 结论 我希望通过本文,你已经掌握了使用GridView控件的基本知识及其它一些技巧。我们分析了实现GridView控件的一种方法以及如何控制其内容的生成。在下一篇中,我们将探讨GridView控件的数据来源,并与你共同建立实际的购物篮。
查看本文来源