共用方式為


使用兩個 DropDownList 進行主要/詳細資料篩選 (C#)

作者:Scott Mitchell

下載 PDF

本教學課程會展開主要/詳細數據關聯性,以新增第三層,使用兩個DropDownList控件來選取所需的父和父系記錄。

簡介

上一個教學課程 中,我們已瞭解如何使用填入類別的單一DropDownList來顯示簡單的主要/詳細數據報表,以及顯示屬於所選類別之產品的 GridView。 此報表模式在顯示具有一對多關聯性的記錄時運作良好,而且可以輕鬆地擴充,以用於包含多個一對多關聯性的案例。 例如,訂單項目系統會有對應至客戶、訂單和訂單明細項目的數據表。 指定的客戶可能會有多個訂單,每個訂單都包含多個專案。 這類數據可以向用戶呈現兩個DropDownList和 GridView。 第一個DropDownList會為資料庫中的每一位客戶提供清單專案,而第二個客戶的內容是所選客戶所訂購的訂單。 GridView 會從選取的順序列出明細專案。

雖然 Northwind 資料庫在其、 OrdersOrder Details 數據表中包含Customers標準客戶 / 訂單 / 訂單詳細數據資訊,但這些數據表不會在我們的架構中擷取。 不過,我們仍然可以使用兩個相依的DropDownList來說明。 第一個DropDownList會列出類別,第二個是屬於所選類別的產品。 DetailsView 接著會列出所選產品的詳細數據。

步驟 1:建立和填入類別下拉式清單

我們的第一個目標是新增列出類別的DropDownList。 上述教學課程會詳細檢查這些步驟,但這裡已摘要說明以取得完整性。

MasterDetailsDetails.aspx開啟資料夾中的頁面Filtering、將DropDownList 新增至頁面、將其ID屬性設定為 Categories,然後按兩下智慧標記中的 [設定資料源] 連結。 從 [數據源設定精靈] 中選擇新增數據源。

新增DropDownList的新數據源

圖 1:新增 DropDownList 的新數據源 (按兩下即可檢視大小完整的影像)

新的數據源應該自然成為 ObjectDataSource。 將這個新的 ObjectDataSource CategoriesDataSource 命名為 ,並讓它叫 CategoriesBLLGetCategories() 物件的方法。

選擇使用 CategoriesBLL 類別

圖 2:選擇 [使用 CategoriesBLL 類別] (按兩下即可檢視完整大小的影像)

將 ObjectDataSource 設定為使用 GetCategories () 方法

圖 3:將 ObjectDataSource 設定為使用 GetCategories() 方法 (按鍵即可檢視大小完整的映射)

設定 ObjectDataSource 之後,我們仍然需要指定應該顯示在 DropDownList 中的 Categories 數據源欄位,以及哪一個字段應該設定為清單專案的值。 將 CategoryName 欄位設定為顯示,並 CategoryID 設定為每個清單專案的值。

讓DropDownList顯示CategoryName欄位,並使用 CategoryID 做為值

圖 4:讓 DropDownList 顯示 CategoryName 欄位並使用 CategoryID 作為值 (按兩下即可檢視完整大小的影像)

此時,我們有DropDownList控件 (Categories) 填入數據表中的 Categories 記錄。 當使用者從DropDownList中選擇新的類別時,我們想要進行回傳,以重新整理我們將在步驟 2 中建立的產品DropDownList。 因此,請從 categories DropDownList的智慧標記中檢查 [啟用 AutoPostBack] 選項。

為類別下拉式清單啟用 AutoPostBack

圖 5:為 DropDownList 啟用 AutoPostBack Categories (按兩下以檢視大小完整的映像)

步驟 2:在第二個 DropDownList 中顯示選取類別的產品

Categories完成DropDownList之後,下一個步驟是顯示屬於所選類別的產品DropDownList。 若要達成此目的,請將另一個DropDownList新增至名為 ProductsByCategory的頁面。 Categories如同 DropDownList,為名為 ProductsByCategoryDataSourceProductsByCategory DropDownList 建立新的 ObjectDataSource。

為 ProductsByCategory DropDownList 新增數據源

圖 6:新增 DropDownList 的新 ProductsByCategory 數據源 (按兩下即可檢視大小完整的影像)

建立名為 ProductsByCategoryDataSource 的新 ObjectDataSource

圖 7:建立名為 ProductsByCategoryDataSource 的新 ObjectDataSource (按兩下即可檢視完整大小的映射)

ProductsByCategory由於DropDownList只需要顯示屬於所選類別的產品,所以 ObjectDataSource 會從 ProductsBLL 物件叫用 GetProductsByCategoryID(categoryID) 方法。

[設定數據源 - productsByCategoryDataSource] 視窗的螢幕快照,其中已選取 ProductsBLL,並醒目提示 [下一步] 按鈕。

圖 8:選擇 [使用 ProductsBLL 類別] (按下即可檢視完整大小的影像)

將 ObjectDataSource 設定為使用 GetProductsByCategoryID (categoryID) 方法

圖 9:將 ObjectDataSource 設定為使用 GetProductsByCategoryID(categoryID) 方法 (按兩下以檢視大小完整的映像)

在精靈的最後一個步驟中,我們需要指定 參數的值 categoryID 。 從 Categories DropDownList將此參數指派給選取的專案。

從 Category DropDownList 提取 categoryID 參數值

圖 10:從 Categories DropDownList 提取categoryID參數值 (按一下以檢視大小完整的影像)

設定 ObjectDataSource 後,所有保留專案都是指定用於DropDownList項目顯示和值的數據源字段。 ProductName顯示欄位,並使用 ProductID 欄位做為值。

指定 DropDownList 的 ListItems 文字和值屬性所使用的數據源欄位

圖 11:指定用於DropDownList ListItemText 資料源欄位和 Value 屬性 (按兩下即可檢視大小完整的影像)

設定 ObjectDataSource 和 ProductsByCategory DropDownList 時,我們的頁面會顯示兩個 DropDownList:第一個會列出所有類別,而第二個則會列出屬於所選類別的產品。 當使用者從第一個DropDownList選取新的類別時,回傳將會加入,而第二個DropDownList將會重新系結,其中顯示屬於新選取類別的產品。 圖 12 和 13 會在透過瀏覽器檢視時顯示 MasterDetailsDetails.aspx 作用中。

第一次瀏覽頁面時,就會選取 [排序類別]

圖 12:第一次瀏覽頁面時,[選取][訂用帳戶類別] (按兩下即可檢視完整大小的影像)

選擇不同的類別會顯示新類別的產品

圖 13:選擇不同的類別顯示新類別的產品 (按兩下即可檢視大小完整的影像)

productsByCategory目前,當變更時,DropDownList 不會造成回傳。 不過,一旦新增 DetailsView 以顯示所選產品的詳細數據, (步驟 3) ,就會發生回傳。 因此,從 productsByCategory DropDownList的智慧標記中核取 [啟用 AutoPostBack] 複選框。

啟用產品的 AutoPostBack 功能ByCategory DropDownList

圖 14:啟用DropDownList的 productsByCategory AutoPostBack 功能 (按兩下即可檢視大小完整的映像)

步驟 3:使用 DetailsView 顯示所選產品的詳細數據

最後一個步驟是在 DetailsView 中顯示所選產品的詳細數據。 若要達成此目的,請將DetailsView新增至頁面、將其 ID 屬性 ProductDetails設定為 ,併為其建立新的 ObjectDataSource。 將此 ObjectDataSource 設定為使用DropDownList的選取值ProductsByCategory,從ProductsBLL類別GetProductByProductID(productID)的方法提取其數據,以取得參數的值productID

[設定數據源 - productsByCategoryDataSource] 視窗的螢幕快照,其中已選取 ProductsBLL,並醒目提示 [下一步] 按鈕。

圖 15:選擇 [使用 ProductsBLL 類別 (按兩下以檢視完整大小的影像)

將 ObjectDataSource 設定為使用 GetProductByProductID (productID) 方法

圖 16:將 ObjectDataSource 設定為使用 GetProductByProductID(productID) 方法 (按兩下即可檢視大小完整的映像)

從 ProductsByCategory DropDownList 提取 productID 參數值

圖 17:從 ProductsByCategory DropDownList 提取productID參數值 (按兩下以檢視大小完整的影像)

您可以選擇在 DetailsView 中顯示任何可用的欄位。 我已選擇移除 ProductIDSupplierIDCategoryID 欄位,並重新排序並格式化其餘欄位。 此外,我清除了 DetailsView 的 HeightWidth 屬性,讓 DetailsView 能夠擴充到最能顯示其數據所需的寬度,而不是限製為指定的大小。 完整標記如下所示:

<asp:DetailsView ID="ProductDetails" runat="server"
    AutoGenerateRows="False" DataKeyNames="ProductID"
    DataSourceID="ObjectDataSource1" EnableViewState="False">
    <Fields>
        <asp:BoundField DataField="ProductName"
          HeaderText="Product" SortExpression="ProductName" />
        <asp:BoundField DataField="CategoryName"
          HeaderText="Category" ReadOnly="True"
          SortExpression="CategoryName" />
        <asp:BoundField DataField="SupplierName"
          HeaderText="Supplier" ReadOnly="True"
          SortExpression="SupplierName" />
        <asp:BoundField DataField="QuantityPerUnit"
          HeaderText="Qty/Unit" SortExpression="QuantityPerUnit" />
        <asp:BoundField DataField="UnitPrice"
          DataFormatString="{0:c}" HeaderText="Price"
          HtmlEncode="False" SortExpression="UnitPrice" />
        <asp:BoundField DataField="UnitsInStock"
          HeaderText="UnitsInStock" SortExpression="Units In Stock" />
        <asp:BoundField DataField="UnitsOnOrder"
          HeaderText="UnitsOnOrder" SortExpression="Units On Order" />
        <asp:BoundField DataField="ReorderLevel"
          HeaderText="ReorderLevel" SortExpression="Reorder Level" />
        <asp:CheckBoxField DataField="Discontinued"
          HeaderText="Discontinued" SortExpression="Discontinued" />
    </Fields>
</asp:DetailsView>

花點時間在瀏覽器中試用 MasterDetailsDetails.aspx 頁面。 一目了然,一切可能如預期般運作,但有細微的問題。 當您選擇新的類別時, ProductsByCategory DropDownList 會更新為包含所選類別的產品,但 ProductDetails DetailsView 會繼續顯示先前的產品資訊。 在為選取的類別選擇不同的產品時,會更新DetailsView。 此外,如果您徹底測試,您會發現如果您持續選擇新的類別 (,例如從 Categories DropDownList 選擇 [篩選],然後 [Condiments],則 [Condiments]) 其他每個類別選取專案都會 ProductDetails 重新整理 DetailsView。

為了協助串連此問題,讓我們看看特定的範例。 當您第一次瀏覽頁面時,會選取 [供應專案] 類別,並在DropDownList 中 ProductsByCategory 載入相關產品。 Chai 是選取的產品,其詳細數據會顯示在 DetailsView 中 ProductDetails ,如圖 18 所示。

選取的產品詳細數據會顯示在DetailsView中

圖 18:選取的產品詳細數據會顯示在 DetailsView (按兩下以檢視大小完整的影像)

如果您將類別選取範圍從 [入口] 變更為 [Condiments],就會發生回傳,並 ProductsByCategory 據以更新 DropDownList,但 DetailsView 仍會顯示 Chai 的詳細數據。

先前選取的產品詳細數據仍會顯示

圖 19:先前選取的產品詳細數據仍會顯示 (按鍵即可檢視完整大小的影像)

從清單中挑選新產品會如預期般重新整理 DetailsView。 如果您在變更產品之後挑選新的類別,則 DetailsView 不會再次重新整理。 不過,如果沒有選擇您選取新類別的新產品,則 DetailsView 會重新整理。 世界發生什麼事?

問題是頁面生命週期中的計時問題。 每當要求頁面時,它會在轉譯時繼續執行一些步驟。 在上述其中一個步驟中,ObjectDataSource 控件會檢查其 SelectParameters 值是否已變更。 如果是,系結至 ObjectDataSource 的數據 Web 控件知道它需要重新整理其顯示。 例如,選取新的類別時, ProductsByCategoryDataSource ObjectDataSource 會偵測其參數值已變更,而 ProductsByCategory DropDownList會重新系結其本身,並取得所選類別的產品。

在此情況下所發生的問題在於,ObjectDataSources 檢查變更參數的頁面生命週期點會在重新系結相關聯的數據 Web 控件 之前 發生。 因此,選取新的類別時, ProductsByCategoryDataSource ObjectDataSource 會偵測其參數值中的變更。 不過,DetailsView 所使用的 ProductDetails ObjectDataSource 不會記下任何這類變更,因為 ProductsByCategory DropDownList尚未重新系結。 稍後在生命週期中, ProductsByCategory DropDownList 會將其 ObjectDataSource 重新系結,並抓取新選取類別的產品。 ProductsByCategory當DropDownList的值變更時,ProductDetailsDetailsView的 ObjectDataSource 已經完成其參數值檢查;因此,DetailsView 會顯示其先前的結果。 圖 20 描述此互動。

ProductsByCategory DropDownList 值會在 ProductDetails DetailsView 的 ObjectDataSource 檢查是否有變更之後變更

圖 20ProductsByCategory DropDownList 值會在 DetailsView 的 ObjectDataSource 檢查變更之後 ProductDetails 變更, (按兩下即可檢視完整大小的影像)

若要解決此問題,我們需要在DropDownList系結之後ProductsByCategory明確重新系結 ProductDetails DetailsView。 當DropDownList的事件引發時ProductsByCategory,我們可以呼叫 ProductDetails DetailsView DataBind()DataBound 方法來完成這項作業。 Add the following event handler code to the MasterDetailsDetails.aspx page's code-behind class (refer to the "Programmatically Setting the ObjectDataSource's Parameter Values" for a discussion on how to add an event handler):

protected void ProductsByCategory_DataBound(object sender, EventArgs e)
{
    ProductDetails.DataBind();
}

新增對 DetailsView 方法的DataBind()這個明確呼叫ProductDetails之後,本教學課程會如預期般運作。 圖 21 強調此變更如何解決我們先前的問題。

當 ProductsByCategory DropDownList 的 DataBound 事件引發時,會明確重新整理 ProductDetails DetailsView

圖 21ProductDetails當DropDownList DataBound 的事件引發時ProductsByCategory,會明確重新整理DetailsView (按一下以檢視大小完整的影像)

摘要

DropDownList 可作為主要/詳細數據報表的理想使用者介面元素,其中主要和詳細數據記錄之間有一對多關聯性。 在上述教學課程中,我們已瞭解如何使用單一DropDownList來篩選所選類別所顯示的產品。 在本教學課程中,我們將產品的 GridView 取代為 DropDownList,並使用 DetailsView 來顯示所選產品的詳細數據。 本教學課程中討論的概念可以輕鬆地延伸至涉及多個一對多關聯性的數據模型,例如客戶、訂單和訂單專案。 一般而言,您一律可以為一對多關聯性中的每個「一」實體新增DropDownList。

快樂的程序設計!

關於作者

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

特別感謝

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