views:

60

answers:

4

This has got me stumped. I am trying to find a checkbox in a dynamically loaded asp.net Repeater template. The template works fine and the databinding is fine and everything displays fine but I can't find the control! Any ideas?

This is the repeater code (I have a similar one for the alternate template with a different style):

<%@ Control Language="C#" AutoEventWireup="true" CodeFile="template-tasks-

incomplete.ascx.cs" Inherits="controls_template_tasks_incomplete" %>
<ItemTemplate>
    <div class="task">
        <div class="date"><asp:CheckBox ID="chkIsComplete" runat="server" 
                AutoPostBack="True" /><%# DataBinder.Eval(((RepeaterItem)Container).DataItem, "DateCreated")%></div>
        <div class="description"><%# DataBinder.Eval(((RepeaterItem)Container).DataItem, "TaskDescription")%></div>
    </div>                    
</ItemTemplate>

This is how I load the templates (works fine)

rptTasks.ItemTemplate = LoadTemplate("~/controls/template-tasks-incomplete.ascx");
        rptTasks.AlternatingItemTemplate = LoadTemplate("~/controls/template-tasks-incomplete-alt.ascx");

...and finally this is how I try to find the checkbox (but keeps coming up null)

protected void rptTasks_ItemDataBound(object sender, RepeaterItemEventArgs e)
{
    if (e.Item.ItemType == ListItemType.AlternatingItem || e.Item.ItemType == ListItemType.Item)
    {
        CheckBox chkBoxIsComplete = (CheckBox)e.Item.FindControl("chkIsComplete");

        if (chkBoxIsComplete != null)
        {
            int taskID = (int)DataBinder.Eval(e.Item.DataItem, "TaskID");
        }
    }
}

I can only think the checkbox is buried deeper in the hierarchy somewhere, but I'm not sure how to access it as I thought FindControl would do it.

This is the HTML that's generated:

<ItemTemplate>
<div class="task">
    <div class="date"><input id="ctl00_ContentPlaceHolder1_rptTasks_ctl00_ctl00_chkIsComplete" type="checkbox" name="ctl00$ContentPlaceHolder1$rptTasks$ctl00$ctl00$chkIsComplete" onclick="javascript:setTimeout('__doPostBack(\'ctl00$ContentPlaceHolder1$rptTasks$ctl00$ctl00$chkIsComplete\',\'\')', 0)" />23/08/2010 11:53:00 PM</div>
    <div class="description">test task</div>
</div>                    

A: 

You should probably view the generated html to see exactly where the control is. Barring that if you iterate through all of the controls AND their child controls, you'll eventually locate it.

Chris Lively
+1  A: 

Any reason why you don't implement the OnDataBinding method of the CheckBox?

Example:

<asp:CheckBox ID="chkIsComplete" runat="server"
    AutoPostBack="True" OnDataBinding="chkIsComplete_DataBinding" />

Then in your codebehind you access it:

protected void chkIsComplete_DataBinding(object sender, System.EventArgs e)
{
    CheckBox chk = (CheckBox)(sender);
    int taskID = (int)(Eval("TaskID"));
    // do whatever it is you need to do... you can use Eval to get any record value
    // of the current row and your sender is the actually control itself.
}

This code will run for EACH data bound checkbox so you can do whatever it is you need doing and not have to care about looking for the control. Typically this is the best way of doing databinding because it scopes your code to the control level so you are not having to constantly search for everything and hardcode search names at the record level.

Kelsey
that seems to work on the first binding but on the checkbox postback event it loses it - perhaps because it's a dynamically loaded template.
Dkong
@Dkong not sure the dynamic part should matter. Do you have `ViewState` turned off for the `Repeater`? Remember on a post back the bound code will disappear if you rebind again (not checking for `!IsPostBack`) or `ViewState` is turned off so you have rebind with every request.
Kelsey
+1  A: 

I have this extension method as part of my toolkit:

    /// <summary>
    /// find the control with the given ID, recursively below the root
    /// </summary>
    public static Control FindControlRecursive( this ControlCollection root, string id )
    {
        foreach ( Control control in root )
        {
            if ( control != null && id.Equals( control.ID, StringComparison.InvariantCultureIgnoreCase ) )
            {
                return control;
            }
            else
            {
                Control result = FindControlRecursive( control.Controls, id );
                if ( result != null )
                {
                    return result;
                }
            }
        }

        return null;
    }

usage:

CheckBox chkBoxIsComplete = (CheckBox)e.Item.Controls.FindControlRecursive("chkIsComplete");
dave thieben
A: 

I've never used set the template in code-behind before, but it seems that if your generated HTML includes the line <ItemTemplate> like you indicate, something is not working properly there.

joelt