導(dǎo)言
在前面一章里我們學(xué)習(xí)了如何在一個頁里顯示主/從信息.另外一種經(jīng)常使用的模式就是將主從信息用兩個頁分別顯示.在前面的跨頁面的主/從報表 我們通過GridView顯示所有的supplier來使用這個模式.GridView里包含一個HyperLinkField,鏈接到另外一個頁,并將SupplierID通過querystring傳過去.第二個頁使用GridView列出了選中的supplier提供的product.
這樣的兩頁主/從表也可以用DataList和Repeater來實現(xiàn).唯一的區(qū)別是DataList和Repeater都不提供HyperLinkField.所以我們需要添加一個HyperLink控件或者在ItemTemplate里使用HTML a>.HyperLink的NavigateUrl屬性和a>的href屬性可以通過聲明或者編程來自定義.
本章我們將探討使用Repeater列出categories.每個list item都包含了category的name和description.通過name可以直接鏈接到第二個頁面.在第二頁里用DataList顯示選中的categroy提供的proudct.
第一步: 列出Categories
所有創(chuàng)建主從表的第一步都是顯示主記錄.因此,我們首先在"主"頁里顯示categories.打開DataListRepeaterFiltering文件夾里的CategoryListMaster.aspx頁,添加一個Repeater,然后通過智能標(biāo)簽添加一個ObjectDataSource.使用CategriesBLL類的GetCategories方法配置它.見圖1.
圖 1:使用CategoriesBLL類的GetCategories方法配置ObjectDataSource
我們先不關(guān)心如何添加link.將Repeater的template配置成顯示每個category的name和description.見下面的代碼:
asp:Repeater ID="Repeater1" runat="server" DataSourceID="ObjectDataSource1"
EnableViewState="False">
HeaderTemplate>
ul>
/HeaderTemplate>
ItemTemplate>
li>%# Eval("CategoryName") %> - %# Eval("Description") %>/li>
/ItemTemplate>
FooterTemplate>
/ul>
/FooterTemplate>
/asp:Repeater>
asp:ObjectDataSource ID="ObjectDataSource1" runat="server"
OldValuesParameterFormatString="original_{0}"
SelectMethod="GetCategories" TypeName="CategoriesBLL">
/asp:ObjectDataSource>
完成了上面的代碼后,在瀏覽器里瀏覽頁面.如圖2所示.
圖 2: 列出所有的 Category
第二步: 將Category Name 轉(zhuǎn)換成鏈到Details Page 的Link
我們現(xiàn)在來添加一個link,當(dāng)用戶點擊時,將會鏈到第二個頁(ProductsForCategoryDetails.aspx),在這個頁里顯示"從"信息.這頁里用DataList顯示選中的category的product.為了判斷是哪個category的鏈接被點了,我們需要將CategoryID傳到第二頁.最直接的方法是通過querystring.我們通過名為CategoryID的querystring字段將這個傳給ProductsForCategoryDetails.aspx.例如,查看Beverages categroy下的product,CategoryID為1.用戶將訪問ProductsForCategoryDetails.aspx?CategoryID=1頁.
為了創(chuàng)建hyperlink我們需要添加HyperLink控件或者在ItemTemplate里添加HTMLa>.在每行的hyperlink都相同的情況下,兩種方法都足夠了.對Repeater來說我更愿意使用a>.見下面的代碼:
li>
a href='ProductsForCategoryDetails.aspx?CategoryID=%# Eval("CategoryID") %>'>
%# Eval("CategoryName") %>
/a> - %# Eval("Description") %>
/li>
注意CategoryID可以直接通過href屬性寫入.注意引號和省略號.
li>
asp:HyperLink runat="server" Text='%# Eval("CategoryName") %>'
NavigateUrl='%# "ProductsForCategoryDetails.aspx?CategoryID="
Eval("CategoryID") %>'>
/asp:HyperLink>
- %# Eval("Description") %>
/li>
注意在綁定語法里靜態(tài)URL— ProductsForCategoryDetails.aspx?CategoryID— 是如何直接和Eval("CategoryID")的結(jié)果串聯(lián).
使用HyperLink控件的一個好處是如果需要的話可以編程訪問Repeater的ItemDataBound event handler.例如你可以將沒有關(guān)聯(lián)product的categories顯示為文本,而不是link.將那些沒有關(guān)聯(lián)product的categories的HyperLink的NavigateUrl屬性設(shè)為一個空的字符串,這樣category name就顯示為一個text(而不是link).更多的通過ItemDataBound event handler的編程來格式化DataList和Repeater內(nèi)容的信息請看格式化DataList和Repeater的數(shù)據(jù).如果你在跟著教程做的話,使用上面兩種方法都可以.當(dāng)瀏覽這頁時,每個category name都以link的形式呈現(xiàn),可以鏈接到ProductsForCategoryDetails.aspx頁,并將CategoryID的值傳過去.見圖3.
圖 3: Category Names 現(xiàn)在鏈接到ProductsForCategoryDetails.aspx頁
第三步: 列出選中的Category下的Products
完成CategoryListMaster.aspx頁后,我們現(xiàn)在來完成"從"頁,ProductsForCategoryDetails.aspx.打開這個頁,拖一個DataList控件進(jìn)來,并將ID設(shè)置為ProductsInCategory.然后在智能標(biāo)簽里選擇添加一個名為ProductsInCategoryDataSource的ObjectDataSource.并用ProductsBLL類的GetProductsByCategoryID(categoryID)方法配置它.在INSERT,UPDATE,DELETE標(biāo)簽里選擇None.
圖 4: 使用ProductsBLL類的GetProductsByCategoryID(categoryID)方法配置ObjectDataSource
由于GetProductsByCategoryID(categoryID)方法接收一個參數(shù),所以向?qū)崾疚覀冎付▍?shù)來源.設(shè)置parameter source為QueryString,QueryStringField為CategoryID.
圖 5: 使用Querystring Field 作為Parameter Source
象前面教程里看到的那樣,完成數(shù)據(jù)源配置后,Visual Studio會自動創(chuàng)建一個ItemTemplate列出每個字段的name和value.我們只顯示name,supplier和price.將DataList的RepeatColumns屬性設(shè)為2.完成這些后你的聲明標(biāo)記看起來應(yīng)該和下面差不多:
asp:DataList ID="ProductsInCategory" runat="server" DataKeyField="ProductID"
RepeatColumns="2" DataSourceID="ProductsInCategoryDataSource"
EnableViewState="False">
ItemTemplate>
h5>%# Eval("ProductName") %>/h5>
p>
Supplied by %# Eval("SupplierName") %>br />
%# Eval("UnitPrice", "{0:C}") %>
/p>
/ItemTemplate>
/asp:DataList>
asp:ObjectDataSource ID="ProductsInCategoryDataSource"
OldValuesParameterFormatString="original_{0}" runat="server"
SelectMethod="GetProductsByCategoryID" TypeName="ProductsBLL">
SelectParameters>
asp:QueryStringParameter Name="categoryID" QueryStringField="CategoryID"
Type="Int32" />
/SelectParameters>
/asp:ObjectDataSource>
現(xiàn)在我們來看看效果,先瀏覽CategoryListMater.aspx頁.然后在列出的category上點一個link.這樣就會跳到ProductsForCategoryDetails.aspx頁,并將CategoryID通過querystring傳過去.ProductsInCategoryDataSource ObjectDataSource會返回指定category的product并將它們顯示在DataList中,每行兩個.圖6是點擊Beverages的截圖.
圖 6: 每行兩個的顯示Beverages
第四步: 在ProductsForCategoryDetails.aspx里顯示 Category 信息
當(dāng)用戶在CategoryListMaster.aspx頁點擊一個category時,會跳到ProductsForCategoryDetails.aspx頁并顯示選中的categry下的product.然而在這個頁里并沒有包含哪個category被選中了的信息.用戶可能想點Beverages,但是結(jié)果點了Condiments,這時他沒辦法知道自己是否點錯了.為了剞劂這個問題,我們可以將選中的category信息顯示在ProductsForCategoryDetails.aspx頁的頂部(name和description).在ProductsForCategoryDetails.aspx的Repeater上添加一個FormView.然后通過智能標(biāo)簽添加一個名為CategoryDataSource的ObjectDataSource,并用CategoriesBLL類的GetCategoryByCategoryID(categoryID)方法配置它.
圖 7: 配置CategoryDataSource
在第三步增加ProductsInCategoryDataSource ObjectDataSource時,向?qū)崾疚覀優(yōu)镚etCategoryByCategoryID(categoryID)方法指定輸入?yún)?shù).在這里我們使用和前面一樣的配置,將parameter source設(shè)為QueryString,QueryStringField設(shè)為CategoryID(見圖5).
完成向?qū)Ш?Visual Studio會為FormView自動創(chuàng)建ItemTemplate,EditItemTemplate和InsertItemTemplate.由于只提供只讀的界面,我們將EditItemTemplate和InsertItemTemplate.當(dāng)然你也可以自定義FormView的ItemTemplate.完成上面的操作偶你的標(biāo)記語言應(yīng)該和下面差不多:
asp:FormView ID="FormView1" runat="server" DataKeyNames="CategoryID"
DataSourceID="CategoryDataSource" EnableViewState="False" Width="100%">
ItemTemplate>
h3>
asp:Label ID="CategoryNameLabel" runat="server"
Text='%# Bind("CategoryName") %>' />
/h3>
p>
asp:Label ID="DescriptionLabel" runat="server"
Text='%# Bind("Description") %>' />
/p>
/ItemTemplate>
/asp:FormView>
asp:ObjectDataSource ID="CategoryDataSource" runat="server"
OldValuesParameterFormatString="original_{0}"
SelectMethod="GetCategoryByCategoryID" TypeName="CategoriesBLL">
SelectParameters>
asp:QueryStringParameter Name="categoryID" Type="Int32"
QueryStringField="CategoryID" />
/SelectParameters>
/asp:ObjectDataSource>
注意:我們還在FormView上加了一個HyperLink,它會將用戶鏈回到category頁(CategoryListMaster.aspx).
圖 8: Category 信息顯示在頁的頂部
第五步: 如果選中的Category下無 Products 則顯示一個提示信息
無論有沒有相關(guān)聯(lián)的product,CategoryListMaster.aspx頁都會列出所有的category.如果用戶點了一個無product的category,由于數(shù)據(jù)源為空,在ProductsForCategoryDetails.aspx頁里的DataList將不會顯示.在前面的教程里我們看到了GridView提供了一個EmptyDataText屬性,可以用來在數(shù)據(jù)源無記錄時定義一個消息.不幸的是DataList和Repeater都沒有這個屬性.
為了在category無product時提示用戶,我們需要在頁里加一個Label控件.在沒有匹配的product時將它的Text屬性設(shè)置為要顯示的信息.我們需要根據(jù)DataList有沒有內(nèi)容來編程設(shè)置它的Visible屬性.首先在DataList下加一個Label控件.將它的ID設(shè)為NoProductsMessage,Text設(shè)為"There are no products for the selected category…".然后我們根據(jù)是否有數(shù)據(jù)綁定到ProductsInCategory DataList來設(shè)置它的Visible屬性.這一步需要在數(shù)據(jù)綁定到DataList之后做.對GridView,DetailsView和FormView來說,我們可以為DataBound事件創(chuàng)建一個event handler.在數(shù)據(jù)綁定完后激發(fā).然而DataList和Repeater都沒有DataBound事件.
在這個例子里我們可以在Page_Load事件處理里設(shè)置Label的Visible屬性..由于數(shù)據(jù)綁定到DataList先于Page的Load事件.然而,這種方法在一般情況下不會起作用,因為從ObjectDataSource來的數(shù)據(jù)是在頁面周期之后綁定到DataList.如果顯示的數(shù)據(jù)基于另一個控件的值,例如,象在使用DropDownList顯示主記錄的主/從表的例子里,數(shù)據(jù)直到Page的生命周期的PreRender后才綁定到控件.
一個在所有情況下都起作用的解決方案是在DataList的ItemDataBound(或ItemCreated)事件處理中設(shè)置Visible為False.在這種情況下我們知道數(shù)據(jù)源里至少有一個數(shù)據(jù)項,因此可以隱藏NoProductsMessage Label.除了這個event handler外,我們還需要一個DataList DataBingd的事件處理,來初始化Label的Visible屬性為True.由于DataBinding時間在ItemDataBound事件后激發(fā),Label的Visible屬性會初始化為True.如果有數(shù)據(jù),它會被設(shè)為False.見下面的代碼:
protected void ProductsInCategory_DataBinding(object sender, EventArgs e)
{
// Show the Label
NoProductsMessage.Visible = true;
}
protected void ProductsInCategory_ItemDataBound(object sender, DataListItemEventArgs e)
{
// If we have a data item, hide the Label
if (e.Item.ItemType == ListItemType.Item ||
e.Item.ItemType == ListItemType.AlternatingItem)
NoProductsMessage.Visible = false;
}
在Northwind數(shù)據(jù)庫里的category都和一個或多個product關(guān)聯(lián).為了測試上面的功能,我手動修改了Northwind數(shù)據(jù)庫,將Produce category(CategoryID=7)的product都和Seafood category(CategoryID=8)關(guān)聯(lián)起來.這個可以在Server Explorer里選擇New Query并使用下面的語句:
UPDATE Products SET
CategoryID = 8
WHERE CategoryID = 7
更新了數(shù)據(jù)庫后,回到CategoryListMaster.aspx頁,點Produce鏈接.由于Produce category下面已經(jīng)沒有任何product,所以你會看到"There are no products for the selected category…"的提示,見圖9.
圖 9: 選中的Category下無Product時會顯示一個提示消息
總結(jié)
主/從記錄可以在一個頁上顯示,也可以在兩個頁上分別顯示.在本章里我們學(xué)習(xí)了如何在"主"頁上用Repeater列出category,將相關(guān)的product在"從"頁上列出.每個"主"頁上的項都包含一個鏈到"從"頁的link,并將行的CategoryID值傳過去.
在"從"頁里通過ProductsBLL類的GetProductsByCategoryID(categoryID)方法返回product.categoryID參數(shù)通過querystring的CategoryID值指定.而且我們還將category的細(xì)節(jié)使用FormView顯示在"從"頁里,當(dāng)選中的category無關(guān)聯(lián)product時,會顯示一條提示信息.
祝編程愉快!
作者簡介
Scott Mitchell,著有六本ASP/ASP.NET方面的書,是4GuysFromRolla.com的創(chuàng)始人,自1998年以來一直應(yīng)用 微軟Web技術(shù)。Scott是個獨立的技術(shù)咨詢顧問,培訓(xùn)師,作家,最近完成了將由Sams出版社出版的新作,24小時內(nèi)精通ASP.NET 2.0。他的聯(lián)系電郵為mitchell@4guysfromrolla.com,也可以通過他的博客http://ScottOnWriting.NET與他聯(lián)系。
您可能感興趣的文章:- Repeater中添加按鈕實現(xiàn)點擊按鈕獲取某一行數(shù)據(jù)的方法
- 在ASP.NET 2.0中操作數(shù)據(jù)之二十九:用DataList和Repeater來顯示數(shù)據(jù)
- 在ASP.NET 2.0中操作數(shù)據(jù)之三十:格式化DataList和Repeater的數(shù)據(jù)
- 在ASP.NET 2.0中操作數(shù)據(jù)之三十三:基于DataList和Repeater使用DropDownList過濾的主/從報表
- 在ASP.NET 2.0中操作數(shù)據(jù)之三十五:使用Repeater和DataList單頁面實現(xiàn)主/從報表
- 在ASP.NET 2.0中操作數(shù)據(jù)之四十一:DataList和Repeater數(shù)據(jù)分頁
- 在ASP.NET 2.0中操作數(shù)據(jù)之四十二:DataList和Repeater數(shù)據(jù)排序(一)
- 在ASP.NET 2.0中操作數(shù)據(jù)之四十三:DataList和Repeater數(shù)據(jù)排序(二)
- 在ASP.NET 2.0中操作數(shù)據(jù)之四十四:DataList和Repeater數(shù)據(jù)排序(三)
- 在ASP.NET 2.0中操作數(shù)據(jù)之四十五:DataList和Repeater里的自定義Button