ASP.NET 2.0打造購物車和支付系統(tǒng)

2010-08-28 10:49:52來源:西部e網(wǎng)作者:

    摘要 在本系列文章中,我們基于ASP.NET 2.0構(gòu)建了一個(gè)簡化的在線購物車和PayPal系統(tǒng);并通過這個(gè)示例,對(duì)ASP.NET 2.0中新引入的GridView控件作了深入研究。

  到目前為止,我?guī)缀踉诿恳粋(gè)我參加過的商業(yè)C#.net工程中使用了DataGrid控件;因此,當(dāng)我第一次聽到有關(guān)于GridView是如何提高工作效率時(shí),我飛快地試用了它。DataGrid和GridView都是ASP.NET 2.0中提供的新的控件類,它們?cè)试S你快速容易地顯示表格式數(shù)據(jù);并且當(dāng)在線觀看它們時(shí),它們都能被轉(zhuǎn)換為客戶端HTML表格進(jìn)行顯示。

  一. 簡介

  這是系列文章的第一篇。在本篇中,我們將通過一個(gè)簡單的網(wǎng)上商店示例程序來集中討論GridView控件的一些用法。注意,在每一篇文章中我們都使用相同的源文件。為了觀察本文示例演示效果,你只需要把下載內(nèi)容解壓到你的web服務(wù)器上一個(gè)新的目錄并瀏覽到該目錄名即可。例如,如果你把所有的內(nèi)容解壓到一個(gè)你的web服務(wù)器根目錄下的目錄"gridviewshop",并導(dǎo)航到這個(gè)目錄:
http://www.yourserver.com/gridviewshop

  如果一切順利,那么你應(yīng)該會(huì)看到一個(gè)如下圖1所示的站點(diǎn):

點(diǎn)擊放大此圖片
圖1.本系列文章網(wǎng)上商店演示程序快照。

  二. GridView

  如果你已經(jīng)使用DataGrid實(shí)現(xiàn)了你的系統(tǒng),包括你自己的定制分頁與排序方案,那么,你真正不需要考慮更新到GridView;因?yàn)閺慕K端效果來看,它們都生成相同的內(nèi)容(都生成一個(gè)HTML表格)。然而,如果你剛開始開發(fā)一個(gè)新的系統(tǒng),那么,我建議你使用GridView,特別是如果你想利用它內(nèi)置的分頁與排序功能的話。

  通過在設(shè)計(jì)時(shí)刻設(shè)置各種屬性,你可以控制GridView從外觀到功能等若干方面。在本系列文章后面,我們將會(huì)更為深入地探討這些方面,通過把一些CSS類指派給表格行和表格列頭;當(dāng)然,還要添加一些事件處理器以便允許用戶與每一行數(shù)據(jù)進(jìn)行交互。

  填充GridView類似于填充一個(gè)DataGrid。你只需創(chuàng)建DataSource,然后使用如下代碼把它綁定到GridView即可:

myGridView.DataSource = yourDataSource;
myGridView.DataBind();

  當(dāng)然,借助于.NET 2.0,你還有另一種選擇,那就是創(chuàng)建一個(gè)SqlDataSource并把GridView直接綁定到其上。這是通過設(shè)置它的DataSourceID以匹配你指派給SqlDataSource的ID實(shí)現(xiàn)的,即是:

<!--使用mySqlDataSource的ID創(chuàng)建SqlDataSource-->
<asp:SqlDataSource
id="mySqlDataSource"
runat="server"
DataSourceMode="DataReader"
ConnectionString="<%$ ConnectionStrings:MyNorthwind%>"
SelectCommand="SELECT LastName FROM Employees">
</asp:SqlDataSource>
<!--創(chuàng)建GridView并且指派它的DataSourceID以匹配上面的mySqlDataSource-->
<asp:GridView
id="myGridView"
runat="server"
autogeneratecolumns="true"
DataSourceID="mySqlDataSource"/>

  作為個(gè)人,我并不太看重這種方法,盡管它是微軟推薦的建立你的GridView的方法。我比較喜歡更多地控制我的DataSource;因?yàn),這樣以來我能夠手工過濾它的內(nèi)容甚至更多,這也正是為什么我在這個(gè)商店演示程序中沒有使用這個(gè)方法的原因。

  好,下面讓我們繼續(xù)討論構(gòu)建本文中的商店演示程序。其大致情況是,在一個(gè)頁面上存在兩個(gè)GridViews;你在前面已經(jīng)看到這個(gè)圖像。一個(gè)GridView用于顯示我們的商店的產(chǎn)品,而其它的內(nèi)容對(duì)應(yīng)于購物籃。你能夠容易地把這兩部分拆分到它們各自的頁面中,但是為了簡化起見,我們把這些內(nèi)容放到了一起。

  如果你打開Default.aspx(它包括在本文相應(yīng)的zip源碼文件中),你能夠看到這個(gè)頁面是如何建立的。大多數(shù)HTML僅僅用于實(shí)現(xiàn)包裝之目的;需要注意的是,位于頁面頂部的聲明以及主<form>標(biāo)簽和位于其內(nèi)的<GridView>標(biāo)簽。

  三. 頁面聲明

<%@ page inherits="shop.site" src="cs/site.aspx.cs" %>


  該頁面聲明簡單地告訴我們的頁面它屬于什么命名空間和類。在這個(gè)例子中,我們的命名空間是"shop"而我們的類是"site"。還存在一個(gè)稱為"src"的額外屬性定義,它指向包含該站點(diǎn)類的普通的.cs文本文件。

  我通常在開發(fā)期間,把我的類放在外部.cs文件中,并把它們手工地編譯成.dll文件。當(dāng)我使用Visual Studio時(shí),在開發(fā)期間,我總是習(xí)慣使用預(yù)編譯的dll,因?yàn)樯院,只需要一個(gè)簡單的構(gòu)建即可以生成它們。一旦我完成了相應(yīng)的工作,我都會(huì)把該類構(gòu)建成預(yù)編譯的dll;但是,在開發(fā)期間,我比較喜歡把較多的時(shí)間花費(fèi)在編碼方面而不是編譯上。


    四. 構(gòu)建數(shù)據(jù)

<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>

  如果你仔細(xì)地觀察一下這兩個(gè)GridViews,你會(huì)注意到它們都把AutoGenerateColumns設(shè)置成false。如果沒有這一行,或如果它被設(shè)置為true,那么,當(dāng)我們綁定DataSource時(shí),我們的列就會(huì)被創(chuàng)建。通過關(guān)閉這個(gè)特征,我們能夠使用"Columns"子標(biāo)簽來定義自己的列。使用這一特征,我們能夠創(chuàng)建許多不同類型的列。在這個(gè)演示程序中,我們使用了ImageField和TemplateField列類型。該ImageField列把一個(gè)圖像路徑作為它的值(通過DataImageUrlField屬性),然后在它自己的列內(nèi)顯示該圖像(當(dāng)生成到該頁面時(shí))。

  TemplateField是真正重要的列。它允許你定義一個(gè)HeaderTemplate,一個(gè)ItemTemplate和一個(gè)FooterTemplate。這三個(gè)標(biāo)簽允許你把任何內(nèi)容放到這些地方。其中,HeaderTemplate和FooterTemplate都引用該列的頁眉和頁腳,而ItemTemplate引用body內(nèi)容。

  如果你觀察一下購物籃GridView,你會(huì)看到我們已經(jīng)使用ItemTemplate來顯示購物籃中每一項(xiàng)的名字,價(jià)格和數(shù)量;然后,我們?cè)贔ooterTemplate內(nèi)顯示運(yùn)送費(fèi)用及總價(jià)。上面的片斷僅顯示"name"列和它的頁腳;完整的實(shí)現(xiàn),請(qǐng)參考default.aspx源文件。因?yàn)槊恳涣械捻撁级际庆o態(tài)文本,所以我們使用HeaderTemplate跳過,并代之使用了TemplateField的HeaderText屬性。為了觀察一個(gè)GridView的頁眉和頁腳,你必須把GridView的ShowHeader和ShowFooter屬性都設(shè)置為True。

  使用ItemTemplate的另一個(gè)原因在于,你可以把其它HTML和.net標(biāo)簽放于其中。在這個(gè)演示程序中,存在若干不同的類型標(biāo)簽,包括<input>,<br/>,<hr/>,<asp:Literal>和<a>。把所有這些標(biāo)簽放到一個(gè)ItemTemplate標(biāo)簽內(nèi)的唯一問題是,你必須多做一些工作來預(yù)填充它們,但是并不需要太多工作。第一步是設(shè)置GridView的RowDataBound事件。你可以指派一個(gè)函數(shù)給這個(gè)事件(在我們綁定DataSource后,在每次創(chuàng)建一行時(shí),調(diào)用這個(gè)事件)。你可以在購物籃的GridView屬性中看到這一點(diǎn):
OnRowDataBound="gvBasket_RowDataBound"

  相比之下,產(chǎn)品GridView相應(yīng)的對(duì)應(yīng)功能更簡單些,但是它僅顯示如何填充ItemTemplate而不是Header或Footer模板。

  五. 一個(gè)重要的函數(shù)

  現(xiàn)在,讓我們看一下本示例程序中位于"cs"文件夾下的主要的類文件"site.aspx.cs",并且定位到一個(gè)稱為gvBasket_RowDataBound的函數(shù)。下面是該函數(shù)的主要實(shí)現(xiàn)(當(dāng)然,你可以參考下載源碼檢查該文件的其它部分):

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"]);
   //數(shù)量
   string quantity = Convert.ToString(((DataRowView)e.Row.DataItem)["quantity"]);
((HtmlInputText)e.Row.FindControl("itProductQuantity")).Value = quantity;
   //價(jià)格
   ((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屬性上執(zhí)行一個(gè)切換,這樣我們就能夠區(qū)別我們?cè)谔畛湟粋(gè)Header,F(xiàn)ooter還是Item模板;因?yàn)樗羞@三個(gè)都是單獨(dú)調(diào)用這同一個(gè)函數(shù)。對(duì)于產(chǎn)品和購物籃來說,我們都取得DataControlRowType.DataRow行類型,因?yàn)檫@是我們的ItemTemplate。

  因?yàn)槲覀兘oHTML頁面中的所有控件都確定了唯一的ID,所以我們能夠使用行中的FindControl函數(shù)。這將返回一個(gè)"Object",如果該行中的任何控件有一個(gè)相匹配的ID話。我們可以把它強(qiáng)制轉(zhuǎn)換成我們期望的對(duì)象類型,例如一個(gè)"Literal"或一個(gè)"HtmlInputText"域,然后經(jīng)由它的TextorValue屬性把數(shù)據(jù)指派給它。在每次綁定一個(gè)行時(shí),它都被經(jīng)由GridViewRowEventArgs.Row屬性傳遞給該函數(shù)。使用這種技術(shù),我們就能夠存取該行的DataItem,它包含來自于DataSource的所有的行數(shù)據(jù)。然后,由我們來決定我們想從中提取哪些數(shù)據(jù)以及如何使用它。
在購物籃中,我們從DataItem中提取了名稱,數(shù)量和價(jià)格三列數(shù)據(jù),并且把它們指派給我們嵌入式在ItemTemplate中的相關(guān)控件。對(duì)于DataControlRowType.Footer,情況基本一致,除了我們從會(huì)話狀態(tài)提取DataSource的一個(gè)副本之外(getBasketDt();),因?yàn)槲覀兿胧褂盟行兄械男畔⑸煽傊导斑\(yùn)送費(fèi)用,而不僅僅是傳遞到該函數(shù)中的單行數(shù)據(jù)。

  六. 結(jié)論

  我希望通過本文,你已經(jīng)掌握了使用GridView控件的基本知識(shí)及其它一些技巧。我們分析了實(shí)現(xiàn)GridView控件的一種方法以及如何控制其內(nèi)容的生成。在下一篇中,我們將探討GridView控件的數(shù)據(jù)來源,并與你共同建立實(shí)際的購物籃。

關(guān)鍵詞:ASP.NET2.0購物車支付