locked
Finding Controls in a Repeater Header RRS feed

  • Question

  • User-1513591455 posted

    The rationale behind many Microsoft ASP.NET controls is sound, but at times their implementation is frustrating, and even using VS2008, old issues still exist

    For example, using a repeater, it is possible find controls in a header during databinding by adding a listener to the ItemCreated or ItemDataBound events.

    Once a repeater is bound, only the bound Items are easily accessible through the Items property.  If you subsequently want to get to a control in a header (or footer), there is no obvious method.

    If you perform a recursive search of the repeater and its controls, you will see that the control structure does contain the header.  So, what's an easy way to find controls in the header?

    What I do is add a static helper class to a web site that contains a recursive control finder.  Now, you need to be aware that with repeated items, there will be the same named item within each repeated item (that is ID : client ID and Unique ID are managed to be unique)

    Since a header and footer only exists once, their controls are easier to find by name (assuming there is no control with that name elsewhere in the repeater control descendants).

     

    Here is some code to find controls by name and type

    /// <summary>

    /// Finds the control by name, starting at a control and drilling down

    /// </summary>

    /// <param name="controlName"></param>

    /// <param name="searchStart"></param>

    /// <returns></returns>

    static public Control RecursiveFindControl(string controlName, Control searchStart)

    {

    if (searchStart.ID == controlName)

    return searchStart;

    else

    {

    foreach (Control child in searchStart.Controls)

    {

    Control result = RecursiveFindControl(controlName, child);

    if (result != null)

    return result;

    }

    }

    return null;

    }

    /// <summary>

    /// Finds the first control derived from a particulr type, recursively, starting with the saerch start control and recursively drilling down

    /// </summary>

    /// <param name="controlType"></param>

    /// <param name="searchStart"></param>

    /// <returns></returns>

    static public Control RecursiveFindControl(Type controlType, Control searchStart)

    {

    // if the control is derived from the type passed, return that control

    if (searchStart.GetType().IsSubclassOf(controlType))

    return searchStart;

    else

    {

    // iterate the children

    foreach (Control child in searchStart.Controls)

    {

    Control result = RecursiveFindControl(controlType, child);

    if (result != null)

    return result;

    }

    }

    return null;

    }

    Wednesday, December 12, 2007 5:02 AM

All replies

  • User1730632263 posted

     I use Findcontrol ..

    aspx -

     

      <asp:Repeater ID="r1" runat="server" OnItemDataBound="r1_ItemDataBound">
                    <ItemTemplate>
                        <asp:Label ID="rlable1" runat="server">
                        </asp:Label>                 
                        <br />
                    </ItemTemplate>
                    <HeaderTemplate>
                        <asp:Label ID="headerLabel" runat="server">
                        </asp:Label>
                        <hr />
                    </HeaderTemplate>
                </asp:Repeater>

     

    and in codebehind..

      protected void r1_ItemDataBound(object sender, RepeaterItemEventArgs e)
        {
            if (e.Item.ItemType == ListItemType.Item) // For items
            {
                Label rlable1 = e.Item.FindControl("rlable1") as Label;
                System.Data.DataRowView data = e.Item.DataItem as System.Data.DataRowView;
                rlable1.Text = data["Extra"].ToString();
            }
            else if (e.Item.ItemType == ListItemType.Header) // For Header
            {
                Label headerLabel = e.Item.FindControl("headerLabel") as Label;           
                headerLabel.Text = "Header That I want to Set from Code";
            }       
        }

    Wednesday, December 12, 2007 5:23 AM
  • User-1513591455 posted

    Your code is exactly what you can do during data binding, and I mentioned this in the article.

    But what happens if you want to get to the header controls AFTER the databind is finished, or on a subsequent page postback?  You don't want to be rebinding the repeater again just to get to a control!

    This is where my method comes in.

    Wednesday, December 12, 2007 5:36 AM
  • User-195892214 posted

    Ok, but what about handling events raised by controls in a repeater's header?   I've got a repeater with an ImageButton in the header, and when the image button is clicked, neither the button's Click() event nor the repeater's ItemCommand() event handlers are raised.  Is there any way to handle events from controls in a repeater's header?

    Tuesday, June 3, 2008 9:52 AM
  • User-1513591455 posted

    You can search for a control on each postback during page load or init and explicitely rebind the event handler, which you must do for dynamic controls - then it will fire after page load completes

    Tuesday, June 3, 2008 11:25 AM
  • User-137005556 posted

    Just thought I'd post up my solution to this. Might be more efficient than doing a recursive search. Declare a private variable at the top of the code:-

    Partial Class default
        inherits system.web.ui.page
        private ddl as dropdownlist

    ...and so on

    In my case it's a dropdownlist I want to access when the repeater has finished databinding. Now during the databind simply find this control and assign it to this variable. It will then be accessible afterwards.

    Tuesday, June 24, 2008 3:59 AM
  • User1673405416 posted

     I find this method works:

     To find a control in the header:

    lblControl = repeater1.controls(0).controls(0).findcontrol("lblControl")

    To find a control in the footer:

    lblControl = repeater1.controls(repeater1.controls.count - 1).controls(0).findcontrol("lblControl")

     

    Hope this helps

     

    Rob

    Wednesday, July 16, 2008 9:12 PM
  • User1817551333 posted

    I see quite a few methods of finding controls in any object, so I thought I would pass my home grown way out there for any one interested.
    I have a couple extension methods that come into play.

    1. GetChildren - This is a quick recursive way of getting all of children below an object

    		
     private static IEnumerable<Control> GetChildren(this Control ctrl)
     {
         var children = ctrl.Controls.Cast<Control>();
         return children.SelectMany(GetChildren).Concat(children);
     }
    

    2. FindControlByType<T> and FindControlByType<T> (Mmmm, strongly typed find control) 

    I will give you all 4 versions that I have of the FindControl methods that I have, and explain them

          2.1:  FindControlsByType<T> - Returns a list of T below the parent object. 

          ------------------------------------------------------------------------------------------------------------------------------------------
          Example:  var repeaterItems = Repeater1.FindControlByType<RepeaterItem>()
          ------------------------------------------------------------------------------------------------------------------------------------------

        public static List<t> FindControlsByType<t>(this Control ctrl) { 
    return ctrl.GetChildren().OfType<t>().ToList();
    } </t></t></t>

          2.2:  FindControlsByType<T> - Returns a list of T below the parent object where the predicate is true. 

          ------------------------------------------------------------------------------------------------------------------------------------------
          Example:  var footerTemplate = Repeater1.FindControlByType<RepeaterItem>(x => x.ItemType == ListItemType.Footer) var buttons = footerTemplate.FindControlsByType<LinkButton>(); 
          ------------------------------------------------------------------------------------------------------------------------------------------

        public static List<t> FindControlsByType<t>(this Control ctrl, Predicate<t> where) { 
    return ctrl.GetChildren().OfType<t>().ToList().FindAll(where);
    } </t></t></t></t>

          2.3:  FindControlByType<T> - Returns a single T below the parent object. 

          ------------------------------------------------------------------------------------------------------------------------------------------
          Example:  var repeaterItems = Repeater1.FindControlByType<RepeaterItem>()
          ------------------------------------------------------------------------------------------------------------------------------------------

        public static T FindControlByType<t>(this Control ctrl) { 
    return ctrl.GetChildren().OfType<t>().SingleOrDefault();
    } </t></t>

          2.2:  FindControlsByType<T> - Returns a list of T below the parent object where the predicate is true. 

          ------------------------------------------------------------------------------------------------------------------------------------------
          Example:  var footerTemplate = Repeater1.FindControlByType<RepeaterItem>(x => x.ItemType == ListItemType.Footer)   var addACardLink = footerTemplate.FindControlByType<LinkButton>(x => x.ID == "AddACardLink"); 
          --------------------------------------------------------------------------------------------------------------------------------------

    		public static T FindControlByType<t>(this Control ctrl, Predicate<t> where) { 
    return ctrl.GetChildren().OfType<t>().ToList().FindAll(where).SingleOrDefault();
    } </t></t></t>

    Using these methods, it has really added a lot of stability and at least, some much needed strongly-typed love. I hope someone else begins to use it and finds it helpful.

    Thanks
    Ryan 



     

    Tuesday, August 23, 2011 3:59 PM
  • User69940601 posted

    Ryan,

    I want to thank you for posting your nifty take on various findcontrol scenarios. I noticed that your code has been messed up a bit, probably by some code formatting script, but I figured it out and I am happy about the possibilities provided by your approach.

    Thanks!! (better late than never, right?)

    /Culme

    Friday, September 21, 2012 8:22 AM
  • User942867765 posted

    For this reason (difficult to access), I don't include the header or footer in the repeater.

    Use code like below.  Note that I have only specified one column and no footer, but this shows the idea that the header and footer need not (should not) be included in the repeater!!     Excuse the formatting -- so way too  difficult to make look nice Yell

    <table>

    <tr>

     <td id="tdHdrCol1" runat="server"><asp:label id="lblCol1" runat="server"></asp:label></td>

     </tr>

     <asp:repeater id="repeater1" runat="server">

    <itemtemplate>

    <tr>

           <td id="tdCol1" runat="server"><asp:label id="lblCol1" runat="server"></asp:label></td>

    </tr>

    </itemtemplate>

    </asp:repeater>

    </table>


     

    <asp:label id="lblHeaderCol1" runat="server"></asp:label>

    <asp:repeater id="repeater1"> <itemtemplate><asp:label id="lblCol1" runat="server"></asp:label></itemtemplate></asp:repeater>

    Thursday, March 21, 2013 6:29 PM