2 つの DropDownList でマスター/詳細をフィルター処理する (C#)
このチュートリアルでは、マスター/詳細リレーションシップを拡張して 3 番目のレイヤーを追加します。2 つの DropDownList コントロールを使用して、目的の親レコードと祖父母レコードを選択します。
はじめに
前の チュートリアル では、カテゴリが設定された 1 つの DropDownList と、選択したカテゴリに属する製品を示す GridView を使用して、単純なマスター/詳細レポートを表示する方法について説明しました。 このレポート パターンは、一対多リレーションシップを持ち、複数の一対多リレーションシップを含むシナリオで機能するように簡単に拡張できるレコードを表示する場合に適しています。 たとえば、注文入力システムには、顧客、注文、および注文品目に対応するテーブルがあります。 特定の顧客が複数の注文を持ち、各注文が複数の品目で構成される場合があります。 このようなデータは、2 つの DropDownList と GridView を使用してユーザーに表示できます。 最初の DropDownList には、データベース内の各顧客のリスト アイテムがあり、2 番目の DropDownList の内容は、選択した顧客によって行われる注文です。 GridView では、選択した注文の品目が一覧表示されます。
Northwind データベースには、標準の顧客/注文/注文の詳細情報が Customers
、 Orders
、および Order Details
テーブルに含まれていますが、これらのテーブルはアーキテクチャではキャプチャされません。 それでも、2 つの依存する DropDownList の使用を示すことができます。 最初の DropDownList にはカテゴリが一覧表示され、2 つ目は選択したカテゴリに属する製品が一覧表示されます。 DetailsView では、選択した製品の詳細が一覧表示されます。
手順 1: カテゴリ DropDownList の作成と設定
最初の目標は、カテゴリを一覧表示する DropDownList を追加することです。 これらの手順は、前のチュートリアルで詳しく調べましたが、完全のためにここに要約されています。
フォルダー内のページをMasterDetailsDetails.aspx
Filtering
開き、DropDownList をページに追加し、そのプロパティを ID
にCategories
設定して、スマート タグの [データ ソースの構成] リンクをクリックします。 データ ソース構成ウィザードで、新しいデータ ソースを追加することを選択します。
図 1: DropDownList の新しいデータ ソースを追加する (クリックするとフルサイズの画像が表示されます)
新しいデータ ソースは、当然ながら ObjectDataSource である必要があります。 この新しい ObjectDataSource というCategoriesDataSource
名前を付け、オブジェクトの GetCategories()
メソッドをCategoriesBLL
呼び出すようにします。
図 2: クラスの使用を選択する CategoriesBLL
(クリックするとフルサイズの画像が表示されます)
図 3: メソッドを使用 GetCategories()
するように ObjectDataSource を構成する (クリックするとフルサイズの画像が表示されます)
ObjectDataSource を構成した後も、DropDownList に表示 Categories
するデータ ソース フィールドと、リスト アイテムの値として構成するデータ ソース フィールドを指定する必要があります。 フィールドを CategoryName
表示として設定し、 CategoryID
各リスト アイテムの値として設定します。
図 4: DropDownList にフィールドを CategoryName
表示し、値として使用 CategoryID
する (クリックするとフルサイズの画像が表示されます)
この時点で、テーブルのレコードが設定された DropDownList コントロール (Categories
) があります Categories
。 ユーザーが DropDownList から新しいカテゴリを選択すると、手順 2 で作成する製品の DropDownList を更新するためにポストバックを実行する必要があります。 したがって、DropDownList のスマート タグから [AutoPostBack を有効にする] オプションをcategories
チェックします。
図 5: DropDownList に対して Categories
AutoPostBack を有効にする (クリックするとフルサイズの画像が表示されます)
手順 2: 選択したカテゴリの製品を 2 番目の DropDownList に表示する
DropDownList が Categories
完了したら、次の手順では、選択したカテゴリに属する製品の DropDownList を表示します。 これを行うには、 という名前 ProductsByCategory
のページに別の DropDownList を追加します。 DropDownList と同様にCategories
、 という名前ProductsByCategoryDataSource
の DropDownList のProductsByCategory
新しい ObjectDataSource を作成します。
図 6: DropDownList の新しいデータ ソースを ProductsByCategory
追加する (クリックするとフルサイズの画像が表示されます)
図 7: 名前付きの ProductsByCategoryDataSource
新しい ObjectDataSource を作成する (フルサイズの画像を表示する をクリックします)
ProductsByCategory
DropDownList では、選択したカテゴリに属する製品のみを表示する必要があるため、ObjectDataSource で オブジェクトから メソッドをGetProductsByCategoryID(categoryID)
ProductsBLL
呼び出すようにします。
図 8: クラスの使用を選択する ProductsBLL
(クリックするとフルサイズの画像が表示されます)
図 9: メソッドを使用 GetProductsByCategoryID(categoryID)
するように ObjectDataSource を構成する (クリックするとフルサイズの画像が表示されます)
ウィザードの最後の手順では、 パラメーターの値を指定する categoryID
必要があります。 DropDownList から選択した項目にこのパラメーターを Categories
割り当てます。
図 10: DropDownList からパラメーター値をCategories
プルcategoryID
する (クリックするとフルサイズの画像が表示されます)
ObjectDataSource が構成されている場合、残っているのは、DropDownList のアイテムの表示と値に使用するデータ ソース フィールドを指定することです。 フィールドを ProductName
表示し、フィールドを ProductID
値として使用します。
図 11: DropDownList ListItem
Text
の および Value
プロパティに使用されるデータ ソース フィールドを指定する (フルサイズの画像を表示する をクリックします)
ObjectDataSource と ProductsByCategory
DropDownList が構成されている場合、ページには 2 つの DropDownList が表示されます。1 つ目はすべてのカテゴリを一覧表示し、2 つ目は選択したカテゴリに属する製品を一覧表示します。 ユーザーが最初の DropDownList から新しいカテゴリを選択すると、ポストバックが実行され、2 番目の DropDownList がリバウンドされ、新しく選択したカテゴリに属する製品が表示されます。 図 12 と図 13 は、ブラウザーを介して表示された場合の動作を示 MasterDetailsDetails.aspx
しています。
図 12: 最初にページにアクセスすると、[飲料] カテゴリが選択されています (フルサイズの画像を表示する をクリックします)。
図 13: 別のカテゴリを選択すると、新しいカテゴリの製品が表示されます (フルサイズの画像を表示する をクリックします)
現在、 productsByCategory
DropDownList が変更された場合、ポストバックは発生 しません 。 ただし、選択した製品の詳細を表示する DetailsView を追加した後でポストバックを実行します (手順 3)。 そのため、DropDownList のスマート タグから [AutoPostBack を有効にする] チェック ボックスをproductsByCategory
チェックします。
図 14: DropDownList の AutoPostBack 機能を productsByCategory
有効にする (フルサイズの画像を表示する をクリックします)
手順 3: DetailsView を使用して選択した製品の詳細を表示する
最後の手順では、選択した製品の詳細を DetailsView に表示します。 これを行うには、DetailsView をページに追加し、そのプロパティを ID
に ProductDetails
設定し、新しい ObjectDataSource を作成します。 パラメーターの値として DropDownList の選択した値を ProductsBLL
使用して、クラスの GetProductByProductID(productID)
メソッドからデータを ProductsByCategory
プルするように、この ObjectDataSource を productID
構成します。
図 15: クラスの使用を選択します ProductsBLL
(クリックするとフルサイズの画像が表示されます)
図 16: メソッドを使用 GetProductByProductID(productID)
するように ObjectDataSource を構成する (クリックするとフルサイズの画像が表示されます)
図 17: DropDownList からパラメーター値をProductsByCategory
プルproductID
する (クリックするとフルサイズの画像が表示されます)
DetailsView で使用可能なフィールドを表示することを選択できます。 私は、、SupplierID
、およびCategoryID
フィールドをProductID
削除し、残りのフィールドを並べ替えて書式設定しました。 さらに、DetailsView の Height
プロパティと Width
プロパティをクリアして、指定したサイズに制限するのではなく、データを最適に表示するために必要な幅に 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 が更新されます。 さらに、十分に十分にテストすると、新しいカテゴリ (DropDownList から Categories
飲料を選択し、次に Condiments、Confections など) を継続的に選択すると、他のすべてのカテゴリの選択 ProductDetails
によって DetailsView が更新されることがわかります。
この問題を解決するために、具体的な例を見てみましょう。 最初にページにアクセスすると、[飲料] カテゴリが選択され、関連する製品が DropDownList に ProductsByCategory
読み込まれます。 Chai は選択した製品であり、その詳細は図 18 に示すように DetailsView に表示されます ProductDetails
。
図 18: 選択した製品の詳細が DetailsView に表示される (フルサイズの画像を表示する をクリックします)
カテゴリの選択を飲料から Condiments に変更すると、ポストバックが発生し ProductsByCategory
、それに応じて DropDownList が更新されますが、DetailsView には Chai の詳細が表示されます。
図 19: 以前に選択した製品の詳細はまだ表示されます (フルサイズの画像を表示する場合はクリックします)
リストから新しい製品を選択すると、DetailsView が期待どおりに更新されます。 製品を変更した後に新しいカテゴリを選択した場合、DetailsView は再び更新されません。 ただし、新しい製品を選択する代わりに新しいカテゴリを選択した場合、DetailsView は更新されます。 世界で何が起こっているのですか?
問題は、ページのライフサイクルにおけるタイミングの問題です。 ページが要求されるたびに、レンダリングとしていくつかの手順を実行します。 これらの手順の 1 つで、ObjectDataSource コントロールチェック、値SelectParameters
のいずれかが変更されているかどうかを確認します。 その場合、ObjectDataSource にバインドされたデータ Web コントロールは、表示を更新する必要があることを認識します。 たとえば、新しいカテゴリが選択されている場合、 ProductsByCategoryDataSource
ObjectDataSource は、そのパラメーター値が変更されたことを検出し ProductsByCategory
、DropDownList 自体を再バインドして、選択したカテゴリの製品を取得します。
この状況で発生する問題は、変更されたパラメーターに対して ObjectDataSources がチェックページ ライフサイクルのポイントが、関連付けられているデータ Web コントロールの再バインドの前に発生することです。 したがって、新しいカテゴリを選択すると、 ProductsByCategoryDataSource
ObjectDataSource はパラメーターの値の変更を検出します。 ただし、DetailsView で ProductDetails
使用される ObjectDataSource では、DropDownList がまだリバウンドされていないため ProductsByCategory
、このような変更は記録されません。 ライフサイクルの後半で、 ProductsByCategory
DropDownList は ObjectDataSource に再バインドし、新しく選択したカテゴリの製品を取得します。 ProductsByCategory
DropDownList の値が変更されている間、ProductDetails
DetailsView の ObjectDataSource は既にパラメーター値チェックを実行しているため、DetailsView には以前の結果が表示されます。 この相互作用を図 20 に示します。
図 20: ProductsByCategory
DetailsView の ObjectDataSource が変更を確認した後 ProductDetails
の DropDownList 値の変更 (フルサイズの画像を表示する場合をクリックします)
これを解決するには、DropDownList がバインドされた後に ProductDetails
DetailsView を明示的に再バインドする ProductsByCategory
必要があります。 これを実現するには、DropDownList のDataBind()
イベントが発生したときに ProductsByCategory
DetailsView の DataBound
メソッドを呼び出ProductDetails
します。 ページの分離コード クラスに MasterDetailsDetails.aspx
次のイベント ハンドラー コードを追加します (イベント ハンドラーを追加する方法については、「ObjectDataSource のパラメーター値をプログラムで設定する」を参照してください)。
protected void ProductsByCategory_DataBound(object sender, EventArgs e)
{
ProductDetails.DataBind();
}
DetailsView DataBind()
のメソッドに対するこのProductDetails
明示的な呼び出しが追加されると、チュートリアルは期待どおりに動作します。 図 21 は、これが以前の問題をどのように改善したかを示しています。
図 21: ProductDetails
DropDownList のイベントが発生したときに ProductsByCategory
DetailsView が明示的に更新される (フルサイズのDataBound
画像を表示する場合をクリックします)
まとめ
DropDownList は、マスター レコードと詳細レコードの間に一対多のリレーションシップがあるマスター/詳細レポートの理想的なユーザー インターフェイス要素として機能します。 前のチュートリアルでは、1 つの DropDownList を使用して、選択したカテゴリによって表示される製品をフィルター処理する方法について説明しました。 このチュートリアルでは、製品の GridView を DropDownList に置き換え、DetailsView を使用して選択した製品の詳細を表示しました。 このチュートリアルで説明する概念は、顧客、注文、注文項目など、複数の一対多リレーションシップを含むデータ モデルに簡単に拡張できます。 一般に、一対多リレーションシップの "1" エンティティごとに常に DropDownList を追加できます。
プログラミングに満足!
著者について
7 冊の ASP/ASP.NET 書籍の著者であり、4GuysFromRolla.com の創設者である Scott Mitchell は、1998 年から Microsoft Web テクノロジと協力しています。 Scott は、独立したコンサルタント、トレーナー、ライターとして働いています。 彼の最新の本は サムズは24時間で2.0 ASP.NET 自分自身を教えています。 にアクセスするか、ブログを使用して にアクセスmitchell@4GuysFromRolla.comできます。これは でhttp://ScottOnWriting.NET見つけることができます。
特別な感謝
このチュートリアル シリーズは、多くの役に立つ校閲者によってレビューされました。 このチュートリアルのリード レビュー担当者は、ヒルトン ギーゼナウでした。 今後の MSDN の記事を確認することに関心がありますか? その場合は、 にmitchell@4GuysFromRolla.com行をドロップしてください。