反復値データ連結をサポートするリスト系コントロールはいずれもasp:ListItemコントロールを使ってアイテムの登録が可能だが、このとき以下のようにテキストだけ、あるいはテキストと値の両方を設定することができた。
<asp:ListBox runat="server">
<asp:ListItem Value="1">Item1</asp:ListItem> テキストと値を指定
<asp:LiteItem> Item2</asp:ListItem> テキストだけを指定
</asp:ListBox>
反復値データ連結を行うときには、データソースとリスト・アイテムがどのようにマッピングされるのだろうか? 次のリスト9.5に示すサンプル・プログラムを見ながら解説していくことにしよう。このサンプル・プログラムでは、4種類のデータソースを使って、リスト・ボックスにitem1〜item3の3つのアイテムが登録される。
<%@ PAGE LANGUAGE="C#" %>
<%@ Import Namespace="System.Data" %>
<html>
<head>
<script runat="server">
void Page_Load(object sender, EventArgs e) {
if (!IsPostBack) {
string[] array = { "item1", "item2", "item3" };
listbox1.DataSource = array;
ArrayList arraylist = new ArrayList();
arraylist.Add("item1");
arraylist.Add("item2");
arraylist.Add("item3");
listbox2.DataSource = arraylist;
Hashtable ht = new Hashtable();
ht.Add("item1", "0");
ht.Add("item2", "1");
ht.Add("item3", "2");
listbox3.DataTextField = "Key";
listbox3.DataValueField = "Value";
listbox3.DataSource = ht;
DataTable dt = new DataTable();
dt.Columns.Add(new DataColumn("text", typeof(String)));
dt.Columns.Add(new DataColumn("value", typeof(Int32)));
DataRow dr;
for (int i = 0; i < 3; i++) {
dr = dt.NewRow();
dr[0] = "item" + (i + 1);
dr[1] = i;
dt.Rows.Add(dr);
}
listbox4.DataTextField = "text";
listbox4.DataValueField = "value";
listbox4.DataSource = new DataView(dt);
DataBind();
}
}
</script>
</head>
<body>
<form runat="server">
<asp:ListBox id="listbox1" runat="server" />
<asp:ListBox id="listbox2" runat="server" />
<asp:ListBox id="listbox3" runat="server" />
<asp:ListBox id="listbox4" runat="server" />
<asp:Button Text="Submit" runat="server" />
</form>
</body>
</html>
基本的なマッピング・ルールは、データソースのIEnumerableインターフェイスを利用して要素を1つずつ取り出し、これをstring型に変換して、テキストに設定するというものだ。この場合、値は明示的に設定されず、テキストと値の両方に同じデータが連結されることになる。以下のようにstring型の配列(Arrayオブジェクト)やArrayListオブジェクトなどをデータソースに指定すれば、各要素をアイテムのテキストとして登録することができる。
/* 配列(Arrayオブジェクト)をデータソースに指定 */
string[] array = { "item1", "item2", "item3" };
listbox1.DataSource = array;
/* ArrayList(可変長配列)をデータソースに指定 */
ArrayList arraylist = new ArrayList();
arraylist.Add("item1");
arraylist.Add("item2");
arraylist.Add("item3");
listbox2.DataSource = arraylist;
ところで、このサンプル・プログラムでは「<%# 〜 %>」構文を使わずに、コントロールのDataSourceプロパティに、データソースとなるオブジェクトを代入するコードを利用して、データソースの設定を行っている。これはデータ連結構文と同じ働きをするが、ローカル変数をデータソースに指定できる利点があるため、反復値データ連結ではDataSourceプロパティへの設定の方が好んで用いられる。
それでは、データソースの要素が構造体やクラス・オブジェクトだった場合はどうなるのだろうか。例えば、DictionaryEntry構造体を要素に持つHashtableオブジェクトをデータソースに指定したとしよう。
struct DictionaryEntry {
public object Key {get; set;}
public object Value {get; set;}
}
DictionaryEntry構造体には、要素の登録時に指定したキーと値が保存される、KeyプロパティとValueプロパティが定義されている。このデータを連結するときには、Keyプロパティをテキストとして、Valueプロパティを値としてリスト・アイテムに設定したいはずだ。ところが、反復値データ連結はデータソースの構造までは理解できないため、何も指定しなければ前述したマッピング・ルールによるデータ連結が行われてしまう。すると、DictionaryEntryオブジェクトがstring型に変換された結果、“System.Collections.DictionaryEntry”という文字列が3つアイテムとして登録されてしまう(ToStringメソッドがオーバーライドされていないクラスでは、Object.ToStringメソッドによって完全限定名が返されるため)。
これは明らかに期待した結果ではない。そこで要素のプロパティをデータ連結したければ、コントロールのDataTextFieldプロパティ(または属性)にテキストとして設定するプロパティの名前を、またDataValueFieldプロパティに値として設定するプロパティの名前をそれぞれ指定する必要がある。DictionaryEntry構造体ならば、以下に示すように、DataTextFieldプロパティに“Key”を、DataValueFieldプロパティに“Value”を指定すれば、データ連結されるときにKeyプロパティとValueプロパティが参照され、それがリスト・アイテムに設定される(図9.5)。
/* Hashtableをデータソースに指定 */
Hashtable ht = new Hashtable();
ht.Add("item1", "0");
ht.Add("item2", "1");
ht.Add("item3", "2");
/* Hashtableに格納される要素はDictionaryEntry構造体であり、
これはKeyプロパティとValueプロパティを持つ */
listbox3.DataTextField = "Key";
listbox3.DataValueField = "Value";
listbox3.DataSource = ht;
要素がインデクサを持つオブジェクトであるときには、DataTextFieldプロパティとDataValueFieldプロパティはプロパティ名ではなく、インデクサのパラメータとして参照される。例えば、以下に示すようにDataViewオブジェクトをデータソースに指定したとしよう。ここではtextカラムとvalueカラムを持つDataTableを定義して、このDataTableを元に作成したDataViewオブジェクトをデータソースに設定している。
/* DataTableを作成し、カラムを設定する */
DataTable dt = new DataTable();
dt.Columns.Add(new DataColumn("text", typeof(String)));
dt.Columns.Add(new DataColumn("value", typeof(Int32)));
/* DataTableに要素を登録する */
DataRow dr;
for (int i = 0; i < 3; i++) {
dr = dt.NewRow();
dr[0] = "item" + (i + 1);
dr[1] = i;
dt.Rows.Add(dr);
}
/* カラム名をDataTextFieldとDataValueFieldに指定する */
listbox4.DataTextField = "text";
listbox4.DataValueField = "value";
/* DataViewオブジェクトをデータソースとして指定する */
listbox4.DataSource = new DataView(dt);
こうしてDataViewオブジェクトをデータ連結すると、DataTableに登録された各行がDataRowViewオブジェクトとして取り出され、これを元にリスト・アイテムが作成される。このときDataTextFieldとDataValueFieldを指定すればデータ連結をカスタマイズできるわけだが、DictionaryEntry構造体とは異なり、DataRowViewクラスにはインデクサが定義されているため、両プロパティはDataRowViewのプロパティ名ではなく、インデクサのインデックスとして参照される。このインデクサには、データテーブルのカラム名をインデックスとしてデータが登録されているため、結局さっきと同じように、DataTextFieldに"text"を、DataValueFieldに"value"を設定すれば、目的のデータをリスト・アイテムに設定できるようになる(図9.6)。
このように反復値データ連結を行うには、データソースに格納されている要素のデータ型がどのような構造をしているか調べ、その構造に適したDetaTextFieldとDataValueFieldを指定しなければならないのである。
今回はデータ連結式を単体、あるいはリスト系コントロールのデータソースとして利用する方法について解説した。次回では、データソースから取得した項目を「テンプレート」を用いて表形式で表示する「DataListコントロール」について詳しく見ていく予定だ。
Copyright© Digital Advantage Corp. All Rights Reserved.