开发者

Unable to find control in asp.net Repeater control

开发者 https://www.devze.com 2023-01-12 14:14 出处:网络
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

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>                    


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");


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.


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.


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.


Are you using Header/Footer templates at all? If you are, you need to check the type of template that ItemDataBound() is being called on. ItemDataBound() will be called on every template, including the header and footer. The presence of a HeaderTemplate will trigger ItemDataBound() before it is called on subsequent ItemTemplates, and since the control of interest is not contained in the header, you get nothing with FindControl(). By only calling FindControl() where the the item type that called ItemDataBound() is an Item/AlternatingItem, you prevent null/Nothing from being returned in vain search for your control.

<asp:Repeater ID="rpt" runat="server" OnItemDataBound="rpt_ItemDataBound">

<HeaderTemplate><table><tr><td>Header</td></tr></HeaderTemplate>

<ItemTemplate><tr><td><asp:button id="Button" runat="server"/></td></tr></ItemTemplate>

<FooterTemplate><tr><td>Footer</td></tr></table></FooterTemplate>

</asp:Repeater>

Protected Sub rpt_ItemDataBound(sender As Object, e As System.Web.UI.WebControls.RepeaterItemEventArgs)
  If (e.Item.ItemType = ListItemType.Item) Or (e.Item.ItemType = ListItemType.AlternatingItem) Then
      Dim Button As Button = CType(e.Item.FindControl("Button"), Button)
  End If
End Sub
0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号