一. 简介
这是系列文章的第一篇。在本篇中,我们将通过一个简单的网上商店示例程序来集中讨论GridView控件的一些用法。注意,在每一篇文章中我们都使用相同的源文件。为了观察本文示例演示效果,你只需要把下载内容解压到你的web服务器上一个新的目录并浏览到该目录名即可。例如,如果你把所有的内容解压到一个你的web服务器根目录下的目录"gridviewshop",并导航到这个目录:
http://www.yourserver.com/gridviewshop
如果一切顺利,那么你应该会看到一个如下图1所示的站点:
二. GridView
如果你已经使用DataGrid实现了你的系统,包括你自己的定制分页与排序方案,那么,你真正不需要考虑更新到GridView;因为从终端效果来看,它们都生成相同的内容(都生成一个HTML表格)。然而,如果你刚开始开发一个新的系统,那么,我建议你使用GridView,特别是如果你想利用它内置的分页与排序功能的话。
通过在设计时刻设置各种属性,你可以控制GridView从外观到功能等若干方面。在本系列文章后面,我们将会更为深入地探讨这些方面,通过把一些CSS类指派给表格行和表格列头;当然,还要添加一些事件处理器以便允许用户与每一行数据进行交互。
填充GridView类似于填充一个DataGrid。你只需创建DataSource,然后使用如下代码把它绑定到GridView即可:
1![]() myGridView.DataSource = yourDataSource;
myGridView.DataSource = yourDataSource;
2![]() myGridView.DataBind();
myGridView.DataBind();
 myGridView.DataSource = yourDataSource;
myGridView.DataSource = yourDataSource;2
 myGridView.DataBind();
myGridView.DataBind();当然,借助于.NET 2.0,你还有另一种选择,那就是创建一个SqlDataSource并把GridView直接绑定到其上。这是通过设置它的DataSourceID以匹配你指派给SqlDataSource的ID实现的,即是:
 1![]() <!--使用mySqlDataSource的ID创建SqlDataSource-->
<!--使用mySqlDataSource的ID创建SqlDataSource-->
2![]() <asp:SqlDataSource
<asp:SqlDataSource
3![]() id="mySqlDataSource"
id="mySqlDataSource"
4![]() runat="server"
runat="server"
5![]() DataSourceMode="DataReader"
DataSourceMode="DataReader"
6![]() ConnectionString="<%$ ConnectionStrings:MyNorthwind%>"
ConnectionString="<%$ ConnectionStrings:MyNorthwind%>"
7![]() SelectCommand="SELECT LastName FROM Employees">
SelectCommand="SELECT LastName FROM Employees">
8![]() </asp:SqlDataSource>
</asp:SqlDataSource>
9![]() <!--创建GridView并且指派它的DataSourceID以匹配上面的mySqlDataSource-->
<!--创建GridView并且指派它的DataSourceID以匹配上面的mySqlDataSource-->
10![]() <asp:GridView
<asp:GridView
11![]() id="myGridView"
id="myGridView"
12![]() runat="server"
runat="server"
13![]() autogeneratecolumns="true"
autogeneratecolumns="true"
14![]() DataSourceID="mySqlDataSource"/>
DataSourceID="mySqlDataSource"/>
 <!--使用mySqlDataSource的ID创建SqlDataSource-->
<!--使用mySqlDataSource的ID创建SqlDataSource-->2
 <asp:SqlDataSource
<asp:SqlDataSource3
 id="mySqlDataSource"
id="mySqlDataSource"4
 runat="server"
runat="server"5
 DataSourceMode="DataReader"
DataSourceMode="DataReader"6
 ConnectionString="<%$ ConnectionStrings:MyNorthwind%>"
ConnectionString="<%$ ConnectionStrings:MyNorthwind%>"7
 SelectCommand="SELECT LastName FROM Employees">
SelectCommand="SELECT LastName FROM Employees">8
 </asp:SqlDataSource>
</asp:SqlDataSource>9
 <!--创建GridView并且指派它的DataSourceID以匹配上面的mySqlDataSource-->
<!--创建GridView并且指派它的DataSourceID以匹配上面的mySqlDataSource-->10
 <asp:GridView
<asp:GridView11
 id="myGridView"
id="myGridView"12
 runat="server"
runat="server"13
 autogeneratecolumns="true"
autogeneratecolumns="true"14
 DataSourceID="mySqlDataSource"/>
DataSourceID="mySqlDataSource"/>作为个人,我并不太看重这种方法,尽管它是微软推荐的建立你的GridView的方法。我比较喜欢更多地控制我的DataSource;因为,这样以来我能够手工过滤它的内容甚至更多,这也正是为什么我在这个商店演示程序中没有使用这个方法的原因。
好,下面让我们继续讨论构建本文中的商店演示程序。其大致情况是,在一个页面上存在两个GridViews;你在前面已经看到这个图像。一个GridView用于显示我们的商店的产品,而其它的内容对应于购物篮。你能够容易地把这两部分拆分到它们各自的页面中,但是为了简化起见,我们把这些内容放到了一起。
如果你打开Default.aspx(它包括在本文相应的zip源码文件中),你能够看到这个页面是如何建立的。大多数HTML仅仅用于实现包装之目的;需要注意的是,位于页面顶部的声明以及主<form>标签和位于其内的<GridView>标签。
三. 页面声明
1![]() <%@ page inherits="shop.site" src="cs/site.aspx.cs" %>
<%@ page inherits="shop.site" src="cs/site.aspx.cs" %>
该页面声明简单地告诉我们的页面它属于什么命名空间和类。在这个例子中,我们的命名空间是"shop"而我们的类是"site"。还存在一个称为"src"的额外属性定义,它指向包含该站点类的普通的.cs文本文件。 <%@ page inherits="shop.site" src="cs/site.aspx.cs" %>
<%@ page inherits="shop.site" src="cs/site.aspx.cs" %>我通常在开发期间,把我的类放在外部.cs文件中,并把它们手工地编译成.dll文件。当我使用Visual Studio时,在开发期间,我总是习惯使用预编译的dll,因为稍后,只需要一个简单的构建即可以生成它们。一旦我完成了相应的工作,我都会把该类构建成预编译的dll;但是,在开发期间,我比较喜欢把较多的时间花费在编码方面而不是编译上。
四. 构建数据
 1![]() <asp:GridView
<asp:GridView
2![]() id="gvBasket"
id="gvBasket"
3![]() AutoGenerateColumns="false"
AutoGenerateColumns="false" 
4![]() ShowHeader="True"
ShowHeader="True" 
5![]() ShowFooter="True"
ShowFooter="True"
6![]() DataKeyNames="id"
DataKeyNames="id" 
7![]() OnRowDataBound="gvBasket_RowDataBound"
OnRowDataBound="gvBasket_RowDataBound"
8![]() runat="server">
runat="server"> 
9![]() <Columns>
<Columns>
10![]() <asp:ImageField DataImageurlField="thumb" alternatetext="Product Thumbnail" readonly="true" />
<asp:ImageField DataImageurlField="thumb" alternatetext="Product Thumbnail" readonly="true" />
11![]() <asp:TemplateField HeaderText="Item">
<asp:TemplateField HeaderText="Item">
12![]() <ItemTemplate>
<ItemTemplate>
13![]() <h3><asp:Literal id="litItemName" runat="server" /></h3>
<h3><asp:Literal id="litItemName" runat="server" /></h3>
14![]() </ItemTemplate>
</ItemTemplate>
15![]() <FooterTemplate>
<FooterTemplate>
16![]() <a href="delivery-costs.aspx" title="View the list of delivery charges">Delivery Charges</a>
<a href="delivery-costs.aspx" title="View the list of delivery charges">Delivery Charges</a>
17![]() <br /><hr />
<br /><hr />
18![]() <b>Total</b>
<b>Total</b>
19![]() </FooterTemplate>
</FooterTemplate>
20![]() </asp:TemplateField>
</asp:TemplateField>
21![]() </Columns>
</Columns>
22![]() </asp:GridView>
</asp:GridView>
 <asp:GridView
<asp:GridView2
 id="gvBasket"
id="gvBasket"3
 AutoGenerateColumns="false"
AutoGenerateColumns="false" 4
 ShowHeader="True"
ShowHeader="True" 5
 ShowFooter="True"
ShowFooter="True"6
 DataKeyNames="id"
DataKeyNames="id" 7
 OnRowDataBound="gvBasket_RowDataBound"
OnRowDataBound="gvBasket_RowDataBound"8
 runat="server">
runat="server"> 9
 <Columns>
<Columns>10
 <asp:ImageField DataImageurlField="thumb" alternatetext="Product Thumbnail" readonly="true" />
<asp:ImageField DataImageurlField="thumb" alternatetext="Product Thumbnail" readonly="true" />11
 <asp:TemplateField HeaderText="Item">
<asp:TemplateField HeaderText="Item">12
 <ItemTemplate>
<ItemTemplate>13
 <h3><asp:Literal id="litItemName" runat="server" /></h3>
<h3><asp:Literal id="litItemName" runat="server" /></h3>14
 </ItemTemplate>
</ItemTemplate>15
 <FooterTemplate>
<FooterTemplate>16
 <a href="delivery-costs.aspx" title="View the list of delivery charges">Delivery Charges</a>
<a href="delivery-costs.aspx" title="View the list of delivery charges">Delivery Charges</a>17
 <br /><hr />
<br /><hr />18
 <b>Total</b>
<b>Total</b>19
 </FooterTemplate>
</FooterTemplate>20
 </asp:TemplateField>
</asp:TemplateField>21
 </Columns>
</Columns>22
 </asp:GridView>
</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的函数。下面是该函数的主要实现(当然,你可以参考下载源码检查该文件的其它部分):
 1![]() protected void gvBasket_RowDataBound(object sender, GridViewRowEventArgs e)
protected void gvBasket_RowDataBound(object sender, GridViewRowEventArgs e)
2![]() {
{
3![]() switch( e.Row.RowType )
 switch( e.Row.RowType ) 
4![]() {
 {
5![]() case DataControlRowType.DataRow:
  case DataControlRowType.DataRow:
6![]() //名称/描述
   //名称/描述
7![]() ((Literal)e.Row.FindControl("litItemName")).Text = Convert.ToString(((DataRowView)e.Row.DataItem)["name"]);
   ((Literal)e.Row.FindControl("litItemName")).Text = Convert.ToString(((DataRowView)e.Row.DataItem)["name"]);
8![]() //数量
   //数量
9![]() string quantity = Convert.ToString(((DataRowView)e.Row.DataItem)["quantity"]);
   string quantity = Convert.ToString(((DataRowView)e.Row.DataItem)["quantity"]);
10![]() ((HtmlInputText)e.Row.FindControl("itProductQuantity")).Value = quantity;
((HtmlInputText)e.Row.FindControl("itProductQuantity")).Value = quantity;
11![]() //价格
   //价格
12![]() ((Literal)e.Row.FindControl("litPrice")).Text = String.Format("{0:C2}", Convert.ToDouble(((DataRowView)e.Row.DataItem)["price"]) * Convert.ToInt32(quantity));
   ((Literal)e.Row.FindControl("litPrice")).Text = String.Format("{0:C2}", Convert.ToDouble(((DataRowView)e.Row.DataItem)["price"]) * Convert.ToInt32(quantity)); 
13![]() break;
   break;
14![]() case DataControlRowType.Footer:
  case DataControlRowType.Footer:
15![]() DataTable dtShop = getBasketDt();
   DataTable dtShop = getBasketDt();
16![]() double total = 0.00;
   double total = 0.00;
17![]() for(int i = 0; i < dtShop.Rows.Count; i++)
   for(int i = 0; i < dtShop.Rows.Count; i++)
18![]() {
   {
19![]() total += Convert.ToInt32(dtShop.Rows[i]["quantity"]) * Convert.ToDouble(dtShop.Rows[i]["price"]);
    total += Convert.ToInt32(dtShop.Rows[i]["quantity"]) * Convert.ToDouble(dtShop.Rows[i]["price"]);
20![]() }
   }
21![]() ((Literal)e.Row.FindControl("litTotalQuantity")).Text = Convert.ToString(dtShop.Compute("SUM(quantity)", ""));
   ((Literal)e.Row.FindControl("litTotalQuantity")).Text = Convert.ToString(dtShop.Compute("SUM(quantity)", ""));
22![]() ((Literal)e.Row.FindControl("litDeliveryPrice")).Text = String.Format("{0:C2}", Convert.ToDouble(calcDeliveryCost(total)));
   ((Literal)e.Row.FindControl("litDeliveryPrice")).Text = String.Format("{0:C2}", Convert.ToDouble(calcDeliveryCost(total)));
23![]() ((Literal)e.Row.FindControl("litTotalPrice")).Text = String.Format("{0:C2}", Convert.ToDouble(calcDeliveryCost(total)) + total);
   ((Literal)e.Row.FindControl("litTotalPrice")).Text = String.Format("{0:C2}", Convert.ToDouble(calcDeliveryCost(total)) + total);
24![]() break;
   break;
25![]() }
  }
26![]() }
}
 protected void gvBasket_RowDataBound(object sender, GridViewRowEventArgs e)
protected void gvBasket_RowDataBound(object sender, GridViewRowEventArgs e)2
 {
{3
 switch( e.Row.RowType )
 switch( e.Row.RowType ) 4
 {
 {5
 case DataControlRowType.DataRow:
  case DataControlRowType.DataRow:6
 //名称/描述
   //名称/描述7
 ((Literal)e.Row.FindControl("litItemName")).Text = Convert.ToString(((DataRowView)e.Row.DataItem)["name"]);
   ((Literal)e.Row.FindControl("litItemName")).Text = Convert.ToString(((DataRowView)e.Row.DataItem)["name"]);8
 //数量
   //数量9
 string quantity = Convert.ToString(((DataRowView)e.Row.DataItem)["quantity"]);
   string quantity = Convert.ToString(((DataRowView)e.Row.DataItem)["quantity"]);10
 ((HtmlInputText)e.Row.FindControl("itProductQuantity")).Value = quantity;
((HtmlInputText)e.Row.FindControl("itProductQuantity")).Value = quantity;11
 //价格
   //价格12
 ((Literal)e.Row.FindControl("litPrice")).Text = String.Format("{0:C2}", Convert.ToDouble(((DataRowView)e.Row.DataItem)["price"]) * Convert.ToInt32(quantity));
   ((Literal)e.Row.FindControl("litPrice")).Text = String.Format("{0:C2}", Convert.ToDouble(((DataRowView)e.Row.DataItem)["price"]) * Convert.ToInt32(quantity)); 13
 break;
   break;14
 case DataControlRowType.Footer:
  case DataControlRowType.Footer:15
 DataTable dtShop = getBasketDt();
   DataTable dtShop = getBasketDt();16
 double total = 0.00;
   double total = 0.00;17
 for(int i = 0; i < dtShop.Rows.Count; i++)
   for(int i = 0; i < dtShop.Rows.Count; i++)18
 {
   {19
 total += Convert.ToInt32(dtShop.Rows[i]["quantity"]) * Convert.ToDouble(dtShop.Rows[i]["price"]);
    total += Convert.ToInt32(dtShop.Rows[i]["quantity"]) * Convert.ToDouble(dtShop.Rows[i]["price"]);20
 }
   }21
 ((Literal)e.Row.FindControl("litTotalQuantity")).Text = Convert.ToString(dtShop.Compute("SUM(quantity)", ""));
   ((Literal)e.Row.FindControl("litTotalQuantity")).Text = Convert.ToString(dtShop.Compute("SUM(quantity)", ""));22
 ((Literal)e.Row.FindControl("litDeliveryPrice")).Text = String.Format("{0:C2}", Convert.ToDouble(calcDeliveryCost(total)));
   ((Literal)e.Row.FindControl("litDeliveryPrice")).Text = String.Format("{0:C2}", Convert.ToDouble(calcDeliveryCost(total)));23
 ((Literal)e.Row.FindControl("litTotalPrice")).Text = String.Format("{0:C2}", Convert.ToDouble(calcDeliveryCost(total)) + total);
   ((Literal)e.Row.FindControl("litTotalPrice")).Text = String.Format("{0:C2}", Convert.ToDouble(calcDeliveryCost(total)) + total);24
 break;
   break;25
 }
  }26
 }
}我们要做的第一件事是在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控件的数据来源,并与你共同建立实际的购物篮。
 
                    
                     
                    
                 
                    
                 



 
  
                
            
         
         浙公网安备 33010602011771号
浙公网安备 33010602011771号