記事内に広告が含まれています。

ASP.NET FindControl で テンプレート内のコントロールを探し出す(サンプルあり)

2014年6月25日

ASP.NET のテンプレート機能では、サーバーサイドコントロールの定義を1つ用意しておくことで生成するデータ件数分コントロールを生成してくれます。繰り返し表示されるテーブルのレコードにユーザーコントロールを埋め込んだりするのにとても便利です。例えばこんな感じで TextBox を Repeater の ItemTemplate に1つ用意しておけば、バインドデータの件数分 TextBox を生成してくれます。

ItemTemplate を含む実装コード

<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();
}

ItemTemplate から出力される HTML の確認

ただ、テンプレート内に表示されるコントロールのうち、特定のものにアクセスする際に困ることがあります。例えば、特定の 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">

<input name="Repeater1$ctl01$TextBox1" type="text" value="マイ" id="Repeater1_TextBox1_1">

<input name="Repeater1$ctl02$TextBox1" type="text" value="ミー" id="Repeater1_TextBox1_2">

<input name="Repeater1$ctl03$TextBox1" type="text" value="マイン" id="Repeater1_TextBox1_3">

FindControl メソッドを用いた ItemTemplate 内のコントロール取得

直接 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)
        {
            return;
        }

        Debug.WriteLine(item.ItemIndex + 1 + " つ目の値: " + tbox.Text);

        if (item.ItemIndex == 1)
        {
            tbox.Focus();
        }
    }
}

実行結果

ボタンをクリックすると、ItemIndex が 1(上から二つ目)の TextBox にフォーカスが入ることが確認できます。

サンプルアプリケーション

サンプルアプリケーションは、.NET Framework 4.8 で作成されています。

-ASP.NET