リピータ コントロールと DataList を使用した 2 つのページのマスター/詳細フィルター処理 (C#)

作成者: Scott Mitchell

PDF のダウンロード

このチュートリアルでは、マスター/詳細レポートを 2 ページに分ける方法について説明します。 [マスター] ページでは、Repeater コントロールを使用してカテゴリの一覧をレンダリングします。このリストをクリックすると、ユーザーは 2 列の DataList で選択したカテゴリに属する製品が表示される [詳細] ページに移動します。

はじめに

前の チュートリアル では、DropDownLists を使用して "マスター" レコードを表示し、DataList を使用して "詳細" を表示するマスター/詳細レポートを 1 つの Web ページに表示する方法について説明しました。マスター/詳細レポートに使用されるもう 1 つの一般的なパターンは、1 つの Web ページにマスター レコードを、別のページに詳細を表示することです。 前の 2 ページにわたるマスター/詳細フィルターの チュートリアルでは、GridView を使用してこのパターンを調べ、システム内のすべてのサプライヤーを表示しました。 この GridView には HyperLinkField が含まれていました。これは 2 番目のページへのリンクとしてレンダリングされ、クエリ文字列内の を SupplierID 渡します。 2 番目のページでは、GridView を使用して、選択した仕入先から提供された製品を一覧表示しました。

このような 2 ページのマスター/詳細レポートは、DataList コントロールと Repeater コントロールを使用して実行することもできます。 唯一の違いは、DataList と Repeater のどちらも HyperLinkField コントロールのサポートを提供しない点です。 代わりに、HyperLink Web コントロールまたはアンカー HTML 要素 (<a>) をコントロールの ItemTemplate内に追加する必要があります。 HyperLink の NavigateUrl プロパティまたはアンカーの属性は、宣言型またはプログラム型の href アプローチを使用してカスタマイズできます。

このチュートリアルでは、Repeater コントロールを使用して、1 つのページの箇条書きのカテゴリを一覧表示する例について説明します。 各リスト アイテムには、カテゴリの名前と説明が含まれており、カテゴリ名は 2 番目のページへのリンクとして表示されます。 このリンクをクリックすると、ユーザーは 2 番目のページに移動し、選択したカテゴリに属する製品が DataList に表示されます。

手順 1: 箇条書きのカテゴリを表示する

マスター/詳細レポートを作成する最初の手順は、"マスター" レコードを表示することから始めます。 したがって、最初のタスクは、"マスター" ページにカテゴリを表示することです。 フォルダー内のページをCategoryListMaster.aspxDataListRepeaterFiltering開き、Repeater コントロールを追加し、スマート タグから新しい ObjectDataSource を追加することを選択します。 クラスGetCategoriesの メソッドからCategoriesBLLデータにアクセスするように、新しい ObjectDataSource を構成します (図 1 を参照)。

CategoriesBLL クラスの GetCategories メソッドを使用するように ObjectDataSource を構成する

図 1: クラスの メソッドを使用CategoriesBLLするように ObjectDataSource を構成する (クリックするとフルサイズの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: 各カテゴリは箇条書きアイテムとして表示されます (クリックするとフルサイズの画像が表示されます)

ユーザーが特定のカテゴリの "詳細" 情報を表示できるようにするには、各箇条書きアイテムへのリンクを追加する必要があります。このリンクをクリックすると、ユーザーは 2 番目のページ (ProductsForCategoryDetails.aspx) に移動します。 この 2 番目のページでは、DataList を使用して、選択したカテゴリの製品が表示されます。 リンクがクリックされたカテゴリを特定するには、何らかのメカニズムを使用して、クリックされたカテゴリを 2 番目の CategoryID ページに渡す必要があります。 1 つのページから別のページにスカラー データを転送する最も簡単で簡単な方法は、このチュートリアルで使用するオプションである querystring を使用することです。 特に、ページでは、 ProductsForCategoryDetails.aspx 選択した categoryID 値が という名前 CategoryIDのクエリ文字列フィールドを介して渡される必要があります。 たとえば、 が 1 の飲料カテゴリ CategoryID の製品を表示するには、 にアクセス 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の メソッドは文字列 ("CategoryID") を引用符で区切hrefるのでEval、属性の値をアポストロフィ (およびメモ引用符) で区切るようにしてください。 または、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 が、文字列連結を使用して databinding 構文内のの結果 Eval("CategoryID") にどのように追加されるかに注意してください。

HyperLink コントロールを使用する利点の 1 つは、必要に応じて、Repeater の ItemDataBound イベント ハンドラーからプログラムでアクセスできることです。 たとえば、関連付けられた製品のないカテゴリのリンクとしてではなく、カテゴリ名をテキストとして表示できます。 このようなチェックは、イベント ハンドラーでプログラムによってItemDataBound実行できます。関連付けられた製品のないカテゴリの場合、HyperLink の プロパティを空白のNavigateUrl文字列に設定すると、その特定のカテゴリ名が (リンクとしてではなく) プレーン テキストとしてレンダリングされます。 イベント ハンドラーを使用したプログラム ロジックに 基づいて DataList と Repeater の内容を書式設定する方法の詳細については、DataList と Repeater のデータに基づく書式設定に関するチュートリアルを ItemDataBound 参照してください。

フォローしている場合は、ページでアンカー要素または HyperLink 制御アプローチを自由に使用できます。 この方法に関係なく、ブラウザーを介してページを表示する場合、各カテゴリ名は への ProductsForCategoryDetails.aspxリンクとしてレンダリングされ、該当 CategoryID する値を渡す必要があります (図 3 を参照)。

カテゴリ名がProductsForCategoryDetails.aspxにリンクされるようになりました

図 3: [カテゴリ名] リンク先 ProductsForCategoryDetails.aspx (クリックするとフルサイズの画像が表示されます)

手順 3: 選択したカテゴリに属する製品を一覧表示する

ページが CategoryListMaster.aspx 完成したら、"詳細" ページ ProductsForCategoryDetails.aspxの実装に注意を向ける準備ができました。 このページを開き、ツールボックスから Designer に DataList をドラッグし、そのプロパティを IDProductsInCategory設定します。 次に、DataList のスマート タグから、新しい ObjectDataSource をページに追加し、 という名前を付けます ProductsInCategoryDataSource。 クラスの GetProductsByCategoryID(categoryID) メソッドをProductsBLL呼び出すように構成します。INSERT タブ、UPDATE タブ、DELETE タブのドロップダウン リストを (None) に設定します。

ProductsBLL クラスの GetProductsByCategoryID(categoryID) メソッドを使用するように ObjectDataSource を構成する

図 4: クラスの メソッドを使用ProductsBLLするように ObjectDataSource を構成する (クリックするとフルサイズのGetProductsByCategoryID(categoryID)画像が表示されます)

メソッドは GetProductsByCategoryID(categoryID) 入力パラメーター (categoryID) を受け取るので、データ ソースの選択ウィザードでは、パラメーターのソースを指定する機会が提供されます。 QueryStringField CategoryIDを使用して、パラメーター ソースを QueryString に設定します。

パラメーターのソースとして Querystring フィールド CategoryID を使用する

図 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 渡します。 その ProductsInCategoryDataSource 後、 の ProductsForCategoryDetails.aspx ObjectDataSource は、指定されたカテゴリの製品のみを取得し、DataList に表示します。これにより、行ごとに 2 つの製品がレンダリングされます。 図 6 は、飲料を表示するときの の ProductsForCategoryDetails.aspx スクリーンショットを示しています。

飲み物は、行ごとに 2 つ表示されます

図 6: 行ごとに 2 つの飲料が表示されます (フルサイズの画像を表示するには、ここをクリックします)

手順 4: ProductsForCategoryDetails.aspxにカテゴリ情報を表示する

ユーザーが で CategoryListMaster.aspxカテゴリをクリックすると、選択したカテゴリに ProductsForCategoryDetails.aspx 属する製品が表示されます。 ただし、 では ProductsForCategoryDetails.aspx 、選択されたカテゴリに関する視覚的な手掛かりはありません。 飲み物をクリックすることを意図したが、誤って Condiments をクリックしたユーザーは、 に到達 ProductsForCategoryDetails.aspxした後に自分の間違いを認識する方法がありません。 この潜在的な問題を軽減するために、選択したカテゴリ (名前と説明) に関する情報をページの上部に ProductsForCategoryDetails.aspx 表示できます。

これを実現するには、 の Repeater コントロール ProductsForCategoryDetails.aspxの上に FormView を追加します。 次に、FormView のスマート タグの という名前CategoryDataSourceの新しい ObjectDataSource をページに追加し、クラスの GetCategoryByCategoryID(categoryID) メソッドをCategoriesBLL使用するように構成します。

CategoriesBLL クラスの GetCategoryByCategoryID(categoryID) メソッドを使用して Category に関する情報にアクセスする

図 7: クラスの メソッドを使用してカテゴリにCategoriesBLL関する情報にアクセスする (フルサイズのGetCategoryByCategoryID(categoryID)画像を表示する をクリックします)

手順 3 で追加した ProductsInCategoryDataSource ObjectDataSource と同様に、 CategoryDataSource's データ ソースの構成ウィザードによって、メソッドの入力パラメーターのソースの入力が GetCategoryByCategoryID(categoryID) 求められます。 以前とまったく同じ設定を使用し、パラメーター ソースを QueryString に設定し、QueryStringField 値を に CategoryID 設定します (図 5 を参照)。

ウィザードが完了すると、Visual Studio によって FormView の 、EditItemTemplate、および InsertItemTemplate が自動的に作成ItemTemplateされます。 読み取り専用インターフェイスを提供しているので、 と InsertItemTemplateを自由に削除EditItemTemplateできます。 また、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 に加えて、ユーザーをカテゴリの一覧に戻す HyperLink コントロールを FormView の上に追加しました (CategoryListMaster.aspx)。 このリンクを他の場所に配置するか、完全に省略してください。

ページの上部にカテゴリ情報が表示されるようになりました

図 8: ページの上部にカテゴリ情報が表示されるようになりました (クリックするとフルサイズの画像が表示されます)

手順 5: 選択したカテゴリに属する製品がない場合にメッセージを表示する

このページには CategoryListMaster.aspx 、関連する製品があるかどうかに関係なく、システム内のすべてのカテゴリが一覧表示されます。 ユーザーが関連付けられた製品のないカテゴリをクリックした場合、データ ソースには項目がないため、 の ProductsForCategoryDetails.aspx DataList はレンダリングされません。 過去のチュートリアルで説明したように、GridView には、データ ソースにレコードがない場合に表示するテキスト メッセージを指定するために使用できるプロパティが用意 EmptyDataText されています。 残念ながら、DataList も Repeater にもこのようなプロパティは含まれていません。

選択したカテゴリに一致する製品がないことをユーザーに通知するメッセージを表示するには、一致する製品がないことを示すメッセージを表示するプロパティが割り当てられているページ Text に Label コントロールを追加する必要があります。 次に、DataList に項目が含まれているかどうかに基づいて、その Visible プロパティをプログラムで設定する必要があります。

これを実現するには、まず DataList の下に Label を追加します。 その ID プロパティを に NoProductsMessage 設定し、その Text プロパティを "選択したカテゴリの製品はありません... " に設定します。次に、DataList にバインドされたデータの有無に基づいて、この Label Visible のプロパティをプログラムで設定する ProductsInCategory 必要があります。 この割り当ては、データが DataList にバインドされた後に行う必要があります。 GridView、DetailsView、および FormView の場合、データバインドが完了した後に発生するコントロールのイベントの DataBound イベント ハンドラーを作成できます。 ただし、DataList と Repeater のどちらもイベントを DataBound 使用できません。

この特定の例では、ページのイベントの Visible 前にデータが DataList に Page_Load 割り当てられるため、イベント ハンドラーで Label の Load プロパティを割り当てることができます。 ただし、ObjectDataSource からのデータはページのライフサイクルの後半で DataList にバインドされる可能性があるため、この方法は一般的なケースでは機能しません。 たとえば、表示されるデータが別のコントロールの値に基づいている場合 (たとえば、DropDownList を使用して "マスター" レコードを保持するマスター/詳細レポートを表示する場合など)、ページのライフ サイクルのステージまで PreRender データ Web コントロールにデータが再バインドされないことがあります。

すべてのケースで機能する 1 つの解決策は、 または AlternatingItemの項目型ItemFalseバインドするときに、DataList ItemDataBound の (または ItemCreated) イベント ハンドラーで プロパティを に割り当てることVisibleです。 このような場合は、データ ソースに少なくとも 1 つのデータ項目があるため、Label を 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 データベース内のすべてのカテゴリは、1 つ以上の製品に関連付けられています。 この機能をテストするために、このチュートリアル用に Northwind データベースを手動で調整し、Produce カテゴリ (CategoryID = 7) に関連付けられているすべての製品をシーフード カテゴリ (CategoryID = 8) に再割り当てしました。 これは、新しいクエリを選択し、次UPDATEのステートメントを使用して、サーバー エクスプローラーから実現できます。

UPDATE Products SET
    CategoryID = 8
WHERE CategoryID = 7

それに応じてデータベースを更新した後、ページに CategoryListMaster.aspx 戻り、[生成] リンクをクリックします。 [生産] カテゴリに属する製品がなくなったため、"選択したカテゴリの製品はありません。" が表示されます。メッセージを表示します(図 9 を参照)。

選択したカテゴリに属する製品がない場合は、メッセージが表示されます

図 9: 選択したカテゴリに属する製品がない場合は、メッセージが表示されます (フルサイズの画像を表示する をクリックします)。

まとめ

マスター/詳細レポートでは、マスター レコードと詳細レコードの両方を 1 つのページに表示できますが、多くの Web サイトでは 2 つの Web ページに分かれています。 このチュートリアルでは、"マスター" Web ページの Repeater と [詳細] ページに一覧表示されている関連製品を使用して、箇条書きリストにリストされているカテゴリを使用して、このようなマスター/詳細レポートを実装する方法について説明しました。 マスター Web ページの各リスト アイテムには、行 CategoryID の値に沿って渡された詳細ページへのリンクが含まれていました。

指定したサプライヤーの製品を取得する詳細ページでは、 クラスの GetProductsByCategoryID(categoryID) メソッドをProductsBLL使用して行われました。 パラメーター値は categoryID 、パラメーター ソースとして querystring 値を CategoryID 使用して宣言によって指定されました。 また、FormView を使用して詳細ページにカテゴリの詳細を表示する方法と、選択したカテゴリに属する製品がない場合にメッセージを表示する方法についても説明しました。

幸せなプログラミング!

著者について

7 冊の ASP/ASP.NET 書籍の著者であり、 4GuysFromRolla.com の創設者である Scott Mitchell は、1998 年から Microsoft Web テクノロジと協力しています。 Scott は独立したコンサルタント、トレーナー、ライターとして働いています。 彼の最新の本は サムズ・ティーチ・自分自身 ASP.NET 24時間で2.0です。 にアクセスmitchell@4GuysFromRolla.comすることも、ブログを介して アクセスすることもできます。これは でhttp://ScottOnWriting.NET確認できます。

特別な感謝...

このチュートリアル シリーズは、多くの役立つ校閲者によってレビューされました。 このチュートリアルのリード レビュー担当者は、Zack Jones と Liz Shulok でした。 今後の MSDN 記事の確認に関心がありますか? その場合は、 に行mitchell@4GuysFromRolla.comをドロップしてください。