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;
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";
}
}
Somnath Mali
.NET Developer , Pune INDIA.
Please Mark As Answer If my reply helped you.
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!
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?
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
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.
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 FindControlsByType(this Control ctrl) { return ctrl.GetChildren().OfType().ToList(); }
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 FindControlsByType(this Control ctrl, Predicate where) { return ctrl.GetChildren().OfType().ToList().FindAll(where); }
2.3: FindControlByType<T> - Returns a single T below the parent object.
------------------------------------------------------------------------------------------------------------------------------------------ Example: var repeaterItems = Repeater1.FindControlByType<RepeaterItem>() ------------------------------------------------------------------------------------------------------------------------------------------
public static T FindControlByType(this Control ctrl) { return ctrl.GetChildren().OfType().SingleOrDefault(); }
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(this Control ctrl, Predicate where) { return ctrl.GetChildren().OfType().ToList().FindAll(where).SingleOrDefault(); }
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.
sbyard
Contributor
5891 Points
1196 Posts
Finding Controls in a Repeater Header
Dec 12, 2007 09:02 AM|LINK
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;}
somnathmali
Contributor
2632 Points
422 Posts
Re: Finding Controls in a Repeater Header
Dec 12, 2007 09:23 AM|LINK
I use Findcontrol ..
aspx -
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";
}
}
.NET Developer , Pune INDIA.
Please Mark As Answer If my reply helped you.
sbyard
Contributor
5891 Points
1196 Posts
Re: Finding Controls in a Repeater Header
Dec 12, 2007 09:36 AM|LINK
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.
talleman@lum...
Participant
1230 Points
264 Posts
Re: Finding Controls in a Repeater Header
Jun 03, 2008 01:52 PM|LINK
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?
sbyard
Contributor
5891 Points
1196 Posts
Re: Finding Controls in a Repeater Header
Jun 03, 2008 03:25 PM|LINK
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
BrianOConnell
Contributor
4445 Points
830 Posts
Re: Finding Controls in a Repeater Header
Jun 24, 2008 07:59 AM|LINK
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.
RobTheBlackK...
Member
40 Points
21 Posts
Re: Finding Controls in a Repeater Header
Jul 17, 2008 01:12 AM|LINK
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
Sentrix
Member
4 Points
2 Posts
Re: Finding Controls in a Repeater Header
Aug 23, 2011 07:59 PM|LINK
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>()
------------------------------------------------------------------------------------------------------------------------------------------
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>();
------------------------------------------------------------------------------------------------------------------------------------------
2.3: FindControlByType<T> - Returns a single T below the parent object.
------------------------------------------------------------------------------------------------------------------------------------------
Example: var repeaterItems = Repeater1.FindControlByType<RepeaterItem>()
------------------------------------------------------------------------------------------------------------------------------------------
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");
--------------------------------------------------------------------------------------------------------------------------------------
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