使用重複項控件和 DataList (C#) ,跨兩個頁面進行主要/詳細數據篩選

作者:Scott Mitchell

下載 PDF

在本教學課程中,我們將探討如何跨兩個頁面分隔主報表/詳細數據報表。 在 [主版] 頁面中,我們使用 [重複程式] 控件來轉譯類別列表,當按兩下時,會將使用者帶至 [詳細數據] 頁面,其中兩欄 DataList 會顯示屬於所選類別的產品。

簡介

上一個教學課程 中,我們已瞭解如何使用DropDownLists 在單一網頁中顯示主報表/詳細數據報表,以顯示「主要」記錄和DataList以顯示「詳細數據」。用於主要/詳細數據報表的另一個常見模式是讓主記錄在一個網頁上,以及另一個網頁的詳細數據。 在先前的主要 /詳細數據篩選跨兩頁 教學課程中,我們已使用 GridView 檢查此模式,以顯示系統中的所有供應商。 此 GridView 包含 HyperLinkField,它會轉譯為第二個頁面的連結,並在 SupplierID 查詢字串中傳遞 。 第二頁使用 GridView 列出所選供應商所提供的產品。

您也可以使用 DataList 和 Repeater 控制項來完成這類雙頁主版/詳細數據報表。 唯一的差別在於 DataList 和 Repeater 都不支援 HyperLinkField 控件。 相反地,我們必須在控件ItemTemplate內新增 HyperLink Web 控件或錨點 HTML 元素 (<a>) 。 然後可以使用宣告式或程序設計方法來自定義 HyperLink 的屬性 NavigateUrl 或錨點 href 的屬性。

在本教學課程中,我們將探索使用重複項控件在單一頁面上列出專案符號清單的類別範例。 每個清單專案都會包含類別的名稱和描述,而類別名稱會顯示為第二個頁面的連結。 按兩下此連結會讓使用者前往第二個頁面,其中 DataList 會顯示屬於所選類別的產品。

步驟 1:在點符清單中顯示類別

建立任何主要/詳細數據報表的第一個步驟是從顯示「主要」記錄開始。 因此,我們的第一個工作是在 「主版」頁面中顯示類別。 CategoryListMaster.aspx開啟資料夾中的頁面DataListRepeaterFiltering、新增 Repeater 控制件,然後從智慧標記選擇新增 ObjectDataSource。 設定新的 ObjectDataSource,讓它從 CategoriesBLL 類別 GetCategories 的 方法存取其數據 (請參閱圖 1) 。

將 ObjectDataSource 設定為使用 CategoriesBLL 類別的 GetCategories 方法

圖 1:將 ObjectDataSource 設定為使用 CategoriesBLL 類別 GetCategories 的方法 (按兩下以檢視大小完整的影像)

接下來,定義 Repeater 的範本,使其將每個類別名稱和描述顯示為專案符號清單中的專案。 我們尚未擔心每個類別連結都連結到詳細數據頁面。 以下顯示 Repeater 和 ObjectDataSource 的宣告式標記:

<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 所示,Repeater 會轉譯為專案符號清單,其中顯示每個類別的名稱和描述。

每個類別都會顯示為點符清單專案

圖 2:每個類別都會顯示為點符列表專案, (按兩下即可檢視大小完整的影像)

若要允許使用者顯示指定類別的「詳細數據」信息,我們需要將連結新增至每個點符清單專案的連結,按兩下時,會將使用者帶至第二頁 (ProductsForCategoryDetails.aspx) 。 接著,第二頁會使用 DataList 顯示所選類別的產品。 為了判斷已按兩下連結的類別,我們需要透過某些機制,將點選的類別 CategoryID 傳遞至第二頁。 將純量數據從一個頁面傳送到另一個頁面最簡單的最簡單方式,是透過查詢字串,這是我們將在本教學課程中使用的選項。 特別是, ProductsForCategoryDetails.aspx 頁面會預期選取 categoryID 的值會透過名為 CategoryID的querystring字段傳遞。 例如,若要檢視具有 CategoryID 1 個之 [飲料] 類別的產品,使用者將會造訪 ProductsForCategoryDetails.aspx?CategoryID=1

若要在 Repeater 中為每個項目符號列表專案建立超連結,我們需要將 HyperLink Web 控件或 HTML 錨點元素新增至 (<a>) 。ItemTemplate 在針對每個數據列顯示超連結相同的案例中,任一種方法都已足夠。 針對重複項,我偏好使用錨點元素。 若要使用錨點元素,請將 Repeater 的 ItemTemplate 更新為:

<li>
    <a href='ProductsForCategoryDetails.aspx?CategoryID=<%# Eval("CategoryID") %>'>
        <%# Eval("CategoryName") %>
    </a> - <%# Eval("Description") %>
</li>

請注意, CategoryID 可以直接插入錨點元素的 href 屬性中;不過,若要這麼做,請務必 href 使用引號分隔屬性的值 (,並記下引號) ,因為 Eval 屬性內的 href 方法會以引號分隔其字元串 ("CategoryID") 。 或者,可以改用 HyperLink Web 控制項:

<li>
    <asp:HyperLink runat="server" Text='<%# Eval("CategoryName") %>'
        NavigateUrl='<%# "ProductsForCategoryDetails.aspx?CategoryID=" &
            Eval("CategoryID") %>'>
    </asp:HyperLink>
    - <%# Eval("Description") %>
</li>

請注意,URL ProductsForCategoryDetails.aspx?CategoryID 的靜態部分如何附加至直接在數據系結語法中使用字串串連的結果 Eval("CategoryID")

使用 HyperLink 控制件的其中一個優點是,視需要可從 Repeater 的 ItemDataBound 事件處理程式以程式設計方式存取。 例如,您可能會想要將類別名稱顯示為文字,而不是作為沒有相關聯產品之類別的連結。 這類檢查可以在事件處理程式中 ItemDataBound 以程序設計方式執行;對於沒有相關聯產品的類別,HyperLink NavigateUrl 的 屬性可以設定為空白字串,因而導致該特定類別名稱轉譯為純文本 (而非連結) 。 如需根據事件處理程式以程式設計邏輯ItemDataBound格式化 DataList 和 Repeater 內容的詳細資訊,請參閱根據 DataList 和 Repeater 的內容格式化教學課程。

如果您遵循下列步驟,請放心地在頁面中使用錨點元素或 HyperLink 控件方法。 不論方法為何,透過瀏覽器檢視頁面時,每個類別名稱都應該轉譯為的連結 ProductsForCategoryDetails.aspx,並傳入適用的 CategoryID 值 (請參閱圖 3) 。

類別名稱現在連結至 ProductsForCategoryDetails.aspx

圖 3:類別名稱現在連結至 ProductsForCategoryDetails.aspx (按下即可檢視完整大小的影像)

步驟 3:列出屬於所選類別的產品

完成CategoryListMaster.aspx頁面之後,我們就可以開始注意實作「詳細數據」頁面。 ProductsForCategoryDetails.aspx 開啟此頁面,將 DataList 從 [工具箱] 拖曳至 Designer,並將其屬性設定IDProductsInCategory。 接下來,從 DataList 的智慧標記中選擇將新的 ObjectDataSource 新增至頁面,並將它命名為 ProductsInCategoryDataSource。 設定它,讓它呼叫 ProductsBLL 類別 GetProductsByCategoryID(categoryID) 的方法;將 INSERT、UPDATE 和 DELETE 索引標籤中的下拉式清單設定為 [無]) (。

將 ObjectDataSource 設定為使用 ProductsBLL 類別的 GetProductsByCategoryID (categoryID) 方法

圖 4:將 ObjectDataSource 設定為使用 ProductsBLL 類別 GetProductsByCategoryID(categoryID) 的方法 (按兩下即可檢視大小完整的影像)

由於方法 GetProductsByCategoryID(categoryID) 接受輸入參數 (categoryID) ,因此選擇數據源精靈提供我們指定參數來源的機會。 使用 QueryStringField CategoryID將參數來源設定為 QueryString。

使用 Querystring 字段類別目錄識別碼作為參數的來源

圖 5:使用 Querystring 欄位 CategoryID 作為參數的來源 (按兩下即可檢視大小完整的影像)

如先前教學課程中所見,完成 [選擇數據源精靈] 之後,Visual Studio 會自動為 DataList 建立 , ItemTemplate 其中列出每個數據功能變數名稱和值。 將此範本取代為只列出產品名稱、供應商和價格的範本。 此外,將 DataList 的 RepeatColumns 屬性設定為 2。 這些變更之後,DataList 和 ObjectDataSource 的宣告式標記看起來應該如下所示:

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

若要檢視此頁面的運作方式,請從 CategoryListMaster.aspx 頁面開始;接下來,按兩下類別項目符號清單中的連結。 這麼做會帶您前往 ProductsForCategoryDetails.aspx,並透過 CategoryID querystring 傳遞 。 ProductsInCategoryDataSource中的 ProductsForCategoryDetails.aspx ObjectDataSource 接著只會取得指定類別的這些產品,並在 DataList 中顯示它們,其會針對每個數據列轉譯兩個產品。 圖 6 顯示檢視[複本] 時的螢幕快照 ProductsForCategoryDetails.aspx

每個數據列顯示兩個數據列

圖 6:顯示[分列]、[每列顯示兩個] ([按兩下] 以檢視大小完整的影像)

步驟 4:顯示ProductsForCategoryDetails.aspx的類別資訊

當使用者按兩下中的 CategoryListMaster.aspx類別時,會前往 ProductsForCategoryDetails.aspx 並顯示屬於所選類別的產品。 不過,在 中 ProductsForCategoryDetails.aspx ,沒有選取類別的視覺提示。 一位使用者,該使用者意謂著單擊 [異動],但意外按兩下 [Condiments],在到達 ProductsForCategoryDetails.aspx之後便無法實現其錯誤。 為了減輕此潛在問題,我們可以在頁面頂端 ProductsForCategoryDetails.aspx 顯示所選類別的相關信息,也就是其名稱和描述。

若要達成此目的,請在 中的 ProductsForCategoryDetails.aspxRepeater 控件上方新增 FormView。 接下來,從名為的 FormView 智慧標記 CategoryDataSource 將新的 ObjectDataSource 新增至頁面,並將其設定為使用 CategoriesBLL 類別 GetCategoryByCategoryID(categoryID) 的方法。

透過 CategoriesBLL 類別的 GetCategoryByCategoryID (categoryID) 方法存取類別的相關信息

圖 7:透過 CategoriesBLL 類別 GetCategoryByCategoryID(categoryID) 的方法存取類別的相關信息, (按兩下即可檢視大小完整的影像)

如同步驟 3 中新增的 ProductsInCategoryDataSource ObjectDataSource, CategoryDataSource「設定數據源精靈」會提示我們輸入方法輸入參數的來源 GetCategoryByCategoryID(categoryID) 。 使用與之前完全相同的設定,將參數來源設定為 QueryString,並將 QueryStringField 值 CategoryID (設定回圖 5) 。

完成精靈之後,Visual Studio 會自動為 FormView 建立 ItemTemplateEditItemTemplateInsertItemTemplate 。 因為我們提供唯讀介面,因此您可以隨意移除 EditItemTemplateInsertItemTemplate。 此外,您可以隨意自定義 FormView 的 ItemTemplate。 拿掉多餘的範本並自定義 ItemTemplate 之後,FormView 和 ObjectDataSource 的宣告式標記看起來應該如下所示:

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

圖 8 顯示透過瀏覽器檢視此頁面時的螢幕快照。

注意

除了 FormView 之外,我也會在 FormView 上方新增 HyperLink 控件,讓使用者回到 (CategoryListMaster.aspx) 的類別清單。 請隨意將此連結放在其他地方,或完全省略。

類別信息現在會顯示在頁面頂端

圖 8:[類別資訊] 現在會顯示在頁面頂端 (按兩下即可檢視大小完整的影像)

步驟 5:如果沒有產品屬於選取的類別,則顯示訊息

不論 CategoryListMaster.aspx 是否有任何相關聯的產品,頁面都會列出系統中的所有類別。 如果使用者按兩下沒有相關聯產品的類別,將不會轉譯 中的 ProductsForCategoryDetails.aspx DataList,因為其數據源不會有任何專案。 如過去教學課程中所見,GridView 會提供 EmptyDataText 屬性,可用來指定在數據源中沒有記錄時顯示的文字訊息。 可惜的是,DataList 和 Repeater 都沒有這類屬性。

為了顯示訊息,通知用戶選取的類別沒有相符的產品,我們需要將標籤件新增至頁面,其 Text 屬性會指派給訊息,以便在沒有相符產品的情況下顯示。 然後,我們需要根據 DataList 是否包含任何專案,以程式設計方式設定其 Visible 屬性。

若要達成此目的,請從在 DataList 下方新增標籤開始。 將屬性 ID 設定為 NoProductsMessage ,並將其 Text 屬性設定為 [沒有所選類別的產品...]接下來,我們需要根據是否系結任何數據系結至 ProductsInCategory DataList,以程式設計方式設定此標籤Visible的屬性。 在數據系結至 DataList 之後,必須進行此指派。 針對 GridView、DetailsView 和 FormView,我們可以為控件的事件 DataBound 建立事件處理程式,該事件處理程式會在數據系結完成之後引發。 不過,DataList 和 Repeater DataBound 都沒有可用的事件。

在此特定範例中,我們可以在事件處理程式中Page_Load指派 Label 的 Visible 屬性,因為數據會在頁面Load的事件之前指派給 DataList。 不過,此方法在一般情況下無法運作,因為 ObjectDataSource 中的數據可能會在頁面生命週期稍後系結至 DataList。 例如,如果顯示的數據是以另一個控件中的值為基礎,例如使用DropDownList來顯示主要/詳細數據報表來保存「主要」記錄時,數據可能不會重新系結至數據 Web 控件,直到 PreRender 頁面生命週期中的階段為止。

一個適用於所有案例的解決方案,就是在系結 或的項目類型Item時,將 屬性指派VisibleFalse DataList 的 ItemDataBound (或 ItemCreated) 事件處理程式。AlternatingItem 在這種情況下,我們知道數據源中至少有一個數據項,因此可以隱藏 NoProductsMessage 標籤。 除了這個事件處理程式之外,我們也需要 DataList DataBinding 事件的事件處理程式,我們將 Label 的 Visible 屬性初始化為 True。 由於事件 DataBinding 會在事件之前 ItemDataBound 引發,因此 Label 的 Visible 屬性一開始會設定為 True;不過,如果有任何數據項,則會將其設定為 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 資料庫中的所有類別都與一或多個產品相關聯。 若要測試這項功能,我已手動調整本教學課程的 Northwind 資料庫,並將與 [產生] 類別相關聯的所有產品重新指派為 [ CategoryID (CategoryID = 7) ], (= 8) 。 透過選擇 [新增查詢] 並使用下列 UPDATE 語句,即可從 [伺服器總管] 完成此作業:

UPDATE Products SET
    CategoryID = 8
WHERE CategoryID = 7

據以更新資料庫之後,返回 CategoryListMaster.aspx 頁面並按兩下 [產生] 連結。 由於不再有任何屬於 [產生] 類別的產品,您應該會看到「選取的類別沒有產品...」訊息,如圖 9 所示。

如果沒有屬於所選類別的產品,則會顯示一則訊息

圖 9:如果沒有屬於選取類別的產品, (按兩下即可檢視完整大小的影像)

摘要

雖然主要/詳細數據報表可以在單一頁面上同時顯示主要和詳細數據記錄,但在許多網站中,它們會跨兩個網頁分開。 在本教學課程中,我們探討如何使用 「master」 網頁中的重複項,以及 [詳細數據] 頁面中所列的相關聯產品,在點符清單中列出類別,以實作這類主要/詳細數據報表。 主版網頁中的每個清單專案都包含沿著數據列 CategoryID 值傳遞之詳細數據頁面的連結。

在擷取指定供應商這些產品的詳細數據頁面中,是透過 ProductsBLL 類別的 GetProductsByCategoryID(categoryID) 方法來完成。 參數 categoryID 值是以宣告方式使用 CategoryID querystring 值做為參數來源來指定。 我們也探討如何使用 FormView 在詳細數據頁面中顯示類別詳細數據,以及如果沒有屬於所選類別的產品,如何顯示訊息。

快樂的程序設計!

關於作者

Scott Mitchell 是 1998 年以來,1998 年與 Microsoft Web 技術合作的 篇 ASP/ASP.NET 書籍和 4GuysFromRolla.com 作者。 Scott 是獨立的顧問、訓練者和作者。 他的最新書籍是 Sams 在 24 小時內自行 ASP.NET 2.0。 您可以透過mitchell@4GuysFromRolla.com部落格連到,也可以透過其部落格來存取,網址為 http://ScottOnWriting.NET

特別感謝...

本教學課程系列是由許多實用的檢閱者所檢閱。 本教學課程的首席檢閱者是 Zack Jones 和 Liz Shulok。 想要檢閱即將推出的 MSDN 文章嗎? 如果是,請將一行放在 mitchell@4GuysFromRolla.com。