.NET TIPS [ASP.NET]DataGridコントロールを階層表示させるには?デジタルアドバンテージ2004/03/12 |
|
|
DataGridコントロールでデータの一覧を表形式で表示するときに、各行のデータがさらに詳細なデータの一覧を持っていて、それも同時に表示したい場合がある。このようなデータの表示は、次の画面のようにDataGridコントロールを階層化して利用することで実現できる。
DataGridコントロールを階層表示するサンプル・プログラム(nesteddg1.aspx)の実行画面 |
この画面では、フォーラムの一覧と、各フォーラムで公開されている記事の一覧を階層的に表示している。 |
この画面は、今回作成するサンプル・プログラムの実行画面である。ここでは、Build Insiderにあるいくつかのフォーラムの一覧をグリッド表示するとともに、各フォーラムで公開されている最新記事を入れ子になった(ネストした)データグリッドで表示している。
本稿では、このようなDataGridコントロールの階層表示の方法について解説する。ここでポイントとなるのは、階層表示するためのデータの準備と、入れ子になっているDataGridコントロールのデータソースの設定である。
階層表示に使用する「マスター/詳細データ」
階層表示が必要となるようなデータは、一般的に「マスター/詳細データ」や「親子データ」と呼ばれるものだ。例えば、注文データと、注文ごとの注文詳細データは「マスター・データ」と「詳細データ」の関係になっている。それぞれのデータがデータベースのテーブルに格納されている場合には、それらは「マスター/詳細テーブル」と呼ばれる。
通常、これら2つのテーブル間には「リレーション」が設定される。例えば、注文テーブルの主キーとして「注文番号」列を作成したとすると、注文詳細テーブルにも、その親データを示す注文番号を格納するための列を作成し、それを外部キーとして設定する。
ADO.NETのデータセットは、データセットに格納されているデータテーブル間のリレーション(リレーションシップとも呼ばれる)を設定する機能を持っている。データセットにリレーションを作成するには、2つのデータテーブルの列とリレーション名を指定してDataRelationクラス(System.Data名前空間)のオブジェクトを作成し、このオブジェクトをデータセットのRelationsプロパティに追加すればよい。このRelationsプロパティはDataRelationオブジェクトのコレクションである。
ここでは、DataGridコントロールに階層表示するためのマスター/詳細データとしてBuild Insiderで提供しているRSSデータをデータセットに読み込んで利用してみる。
次のコードは、Build InsiderのWebカテゴリとSmall & Mediumカテゴリ、Columnカテゴリの3つのフォーラムのそれぞれの最新記事を記述したRSS情報をデータセットに読み込む。
DataSet ds = new DataSet();
ds.ReadXml("http://www.buildinsider.net/web/rss");
ds.ReadXml("http://www.buildinsider.net/small/rss");
ds.ReadXml("http://www.buildinsider.net/column/rss");
詳細は割愛するが、この結果としてデータセットには、4つのデータテーブルと3つのリレーションが自動的に作成される。ここではこのうち、次の図に示した2つのデータテーブルと、それらのテーブル間をリンクする「channel_item」と名付けられたリレーションを利用する。
@IT(※コードではBuild Insiderになっている)のRSS情報をデータセットで読み込んで得られるデータテーブル |
DataSetクラスのReadXmlメソッドを使用すると、XMLファイルを読み込んでデータテーブルを作成できる。なお実際には、この図で示していない列も各データテーブルには含まれている。本稿ではここに挙げた列のみを扱う。 |
「channel_Id」はフォーラムごとに振られている番号である。ここでは3つのフォーラムについてのRSSファイルを読み込んだので、channelデータテーブルには3つのフォーラムについてのレコードが含まれている。また、itemデータテーブルには各フォーラムでの最新記事についてのレコードが含まれている。
このようなリレーションを持つ2つのデータテーブルでは、親データテーブルにある行(DataRowオブジェクト)のGetChildRowメソッドにより、子データテーブルの行が取得できる。また、親データテーブルのデータビューなどから、行をDataRowViewオブジェクトとして取得した場合には、CreateChildViewメソッドにより子データテーブルのデータビューを取得することができる。
ネストしたDataGridコントロールの記述
次に、階層構造になっている2つのDataGridコントロールを<asp:DataGrid>要素により定義する。これはテンプレート列を用いて、単純にその列内で入れ子となるもう1つの<asp:DataGrid>要素を記述すればよい。大まかな骨組みは次のようになる。
<asp:DataGrid id="MyGrid" ……>
<Columns>
<asp:BoundColumn ……>
<asp:BoundColumn ……>
<asp:TemplateColumn ……>
<ItemTemplate>
<asp:DataGrid id="MySubGrid" ……>
<Columns>
<asp:BoundColumn ……>
<asp:BoundColumn ……>
</Columns>
</asp:DataGrid>
</ItemTemplate>
</asp:TemplateColumn>
</Columns>
</asp:DataGrid>
テンプレート列の利用については「TIPS:[ASP.NET]DataGridコントロールの行に通し番号を付けるには?」などで解説している。
入れ子になったDataGridコントロールのデータ連結
最後にDataGridコントロールにデータセット内のテーブルをデータ連結する。外側の親DataGridコントロールには、単純に親データテーブルをデータソースに指定してデータ連結をすればよいが、問題は入れ子になった子DataGridコントロールのデータソースである。
子DataGridコントロールのデータソースには、親の各行にデータ連結しているデータソース内の要素から、リレーションをたどって得られる子データテーブルを設定する必要がある。このような処理には、それぞれの行のデータ連結時に発生するItemDataBoundイベントを利用できる(このイベントについては「TIPS:[ASP.NET]DataGridコントロールですべての行にアクセスするには?」で解説している)。
このItemDataBoundイベントのイベント・ハンドラとなるメソッドは次のようになる。
void MyGrid_ItemBound(object sender, DataGridItemEventArgs e) {
if (e.Item.ItemType == ListItemType.Item
|| e.Item.ItemType == ListItemType.AlternatingItem) {
DataGrid dg = (DataGrid)e.Item.FindControl("MySubGrid");
dg.DataSource = GetChild(e.Item.DataItem, "channel_item");
dg.DataBind();
}
}
このメソッドでは、「e.Item」が親DataGridコントロールの行を示しているDataGridItemオブジェクトであるが、まずこのオブジェクトの子コントロールとなっている子DataGridコントロールをFindControlメソッドにより取得する。次に、行にデータ連結しているデータソース内の要素(データソースがデータテーブルの場合には、これはDataRowViewオブジェクトである)から、子データテーブルのデータビューを取得する。この処理は次に示すGetChildというメソッドで記述している。子データテーブルのデータビューが得られれば、それを子DataGridコントロールにデータ連結する。
DataRowViewオブジェクトとして得られるデータソース内の要素から、子データテーブルのデータビューを得るためのGetChildメソッドは次のようになる。
DataView GetChild(object item, string relName) {
DataRowView drv = (DataRowView)item;
return drv.CreateChildView(relName);
}
ここでは前述したDataRowViewオブジェクトのCreateChildViewメソッドを呼び出している。
DataGridコントロールを階層表示するサンプル・プログラム
ここまでに3つのポイントについて解説したが、次に示すサンプル・プログラムは、それらを組み合わせて作成したものだ。このプログラムの実行画面はすでに冒頭で示している。
|
|
DataGridコントロールを階層表示するC#のサンプル・プログラム(nesteddg1.aspx) | |
DataSource属性を利用した子DataGridコントロールのデータ連結
上記のサンプル・プログラムでは、プログラム・コードでDataGridコントロールのデータソースを設定したが、DataGridコントロールの定義時にDataSource属性を使用してもデータソースは設定可能だ。この方法を使うと、ItemDataBoundイベントを利用しないで子DataGridコントロールに子データテーブルを連結することができる。
この方法を使って上記のサンプル・プログラムを書き換えると次のようになる。
|
|
DataSource属性を使用してDataGridコントロールを階層表示するC#のサンプル・プログラム(nesteddg2.aspx) | |
DataGridコントロール内に記述したデータ連結式(<%# 〜 %>)においては、「Container」は行を示すDataGridItemオブジェクトである。よって、「Container.DataItem」はDataRowViewオブジェクトであり、最初のサンプル・プログラムと同じGetChildメソッドを使用して、DataSource属性に子データテーブルのデータビューを設定することができる。
なお、DataBindメソッドによるデータ連結の実行は、そのコントロールの子コントロールにも波及する(コントロール・ツリーをたどってすべての子コントロールでデータ連結が実行される)。このため、こちらの方法では子DataGridコントロールでのDataBindメソッドの明示的な呼び出しは不要である。
カテゴリ:Webフォーム 処理対象:DataGridコントロール 使用ライブラリ:DataGridコントロール 使用ライブラリ:DataRelationクラス(System.Data名前空間) 関連TIPS:[ASP.NET]DataGridコントロールの行に通し番号を付けるには? 関連TIPS:[ASP.NET]DataGridコントロールですべての行にアクセスするには? |
「.NET TIPS」 |
- 第2回 簡潔なコーディングのために (2017/7/26)
ラムダ式で記述できるメンバの増加、throw式、out変数、タプルなど、C# 7には以前よりもコードを簡潔に記述できるような機能が導入されている - 第1回 Visual Studio Codeデバッグの基礎知識 (2017/7/21)
Node.jsプログラムをデバッグしながら、Visual Studio Codeに統合されているデバッグ機能の基本の「キ」をマスターしよう - 第1回 明瞭なコーディングのために (2017/7/19)
C# 7で追加された新機能の中から、「数値リテラル構文の改善」と「ローカル関数」を紹介する。これらは分かりやすいコードを記述するのに使える - Presentation Translator (2017/7/18)
Presentation TranslatorはPowerPoint用のアドイン。プレゼンテーション時の字幕の付加や、多言語での質疑応答、スライドの翻訳を行える
|
|