ASP.NET のテンプレート機能では、サーバーサイドコントロールの定義を1つ用意しておくことで生成するデータ件数分コントロールを生成してくれます。繰り返し表示されるテーブルのレコードにユーザーコントロールを埋め込んだりするのにとても便利です。例えばこんな感じで TextBox を Repeater の ItemTemplate に1つ用意しておけば、バインドデータの件数分 TextBox を生成してくれます。
<asp:Repeater ID="Repeater1" runat="server"> <ItemTemplate> <asp:TextBox ID="TextBox1" runat="server" Text="<%# Container.DataItem %>"></asp:TextBox> </ItemTemplate> </asp:Repeater>
データをバインドすると、TextBox が繰り返し表示されます。
protected void Page_Load(object sender, EventArgs e) { List<string> values = new List<string>(); values.Add("アイ"); values.Add("マイ"); values.Add("ミー"); values.Add("マイン"); this.Repeater1.DataSource = values; this.Repeater1.DataBind(); }
ただ、テンプレート内に表示されるコントロールのうち、特定のものにアクセスする際に困ることがあります。例えば、特定の TextBox にフォーカスを設定するシナリオを考えてみましょう。単独の TextBox コントロールのようにサーバーサイドで単純に TextBox1.Focus() と指定することができません。そもそもこの例では TextBox1 を元に生成されたコントロールが4つもあります!
利用するテンプレートよってはサーバーサイドで Intellisense が出て、動きそうな雰囲気のものもありますが、テンプレートに配置されているサーバーサイドコントロールはこのように ASPX 設計時の ID 指定では到達することができません。実際に生成された HTML を見るとより分かるのですが、TextBox1 を元に生成された input エレメント達はそれぞれホストコントロール(ここでは Repeater)の ID と テンプレートコントロール(TextBox)の ID を組み合わせた一意の値が割り当てられています。
<input name="Repeater1$ctl00$TextBox1" type="text" value="アイ" id="Repeater1_TextBox1_0" /><br /> <input name="Repeater1$ctl01$TextBox1" type="text" value="マイ" id="Repeater1_TextBox1_1" /><br /> <input name="Repeater1$ctl02$TextBox1" type="text" value="ミー" id="Repeater1_TextBox1_2" /><br /> <input name="Repeater1$ctl03$TextBox1" type="text" value="マイン" id="Repeater1_TextBox1_3" /><br />
直接 TextBox1 を ID 指定して TextBox にアクセスできないのですが、ASP.NET のテンプレートが提供している FindControl メソッドを利用することでこの ID の差異を吸収してテンプレート内のコントロールを設計時の ID で指定して取得することができます。
protected void Button1_Click(object sender, EventArgs e) { foreach(RepeaterItem item in this.Repeater1.Items) { TextBox tbox = item.FindControl("TextBox1") as TextBox; if (tbox != null) { Debug.WriteLine(item.ItemIndex + 1 + " つ目の値: " + tbox.Text); if (item.ItemIndex == 1) { tbox.Focus(); } } } }
0 件のコメント:
コメントを投稿