If you have worked with any type of container in ASP.NET (Grids, Repeaters, etc.) you know that you cannot simply access any of its underlying collection of controls (for example if you have a div or some other control located inside the repeater) unless you gain a reference to that repeater object first, and then perform a FindControl to search within that repeater container to gain reference to whatever nested control (in my case I wanted to reference a div) you want to work with. Nothing new here. But when you start playing with custom controls or nested controls, then it gets kinda hairy.
But lets make this a little more complex. Lets say that this repeater is ultimately located inside a user control. And that user control resides obviously in your .aspx page. And you have a handler method in the code-behind of your .aspx page that handles a certain event based on another control located inside your repeater. For example lets say in that repeater, you had a LinkButton. You created your own event in the .ascx.cs and are going to wire up the event with an attribute you had set up (“OnAddToCart” instead of OnClick) value of that LinkButton. You created a delegate in the .ascx.cs for that event as well to be handled elsewhere (outside the user control). You then created a handler for that delegate in your .aspx.cs which is simply a method that handles that event. And in that method, you want to set another control’s propertytaht also resides inside that repeater, such as a <div>. In my case I wanted to set the div’s visible property to true or false.
First, lets put this in English" first, something most developers fail miserably to do when posting on their blogs:
“When the user clicks the LinkButton located inside my repeater, I want to handle that event, and based on some logic, set a div’s visible property to true or false. The div also resides inside the repeater.”
How would you do this? Well, let me try to sum that up with the solution.
The goal:
You want to set a property of a control that lives inside a repeater. That repeater lives inside a user control. And that user control lives inside your .aspx page. In my case I wanted to set a property of a div based on a user clicking a LinkButton. And in my case I’m using a custom repeater, custom button…all custom controls. It doesn’t really matter if it’s custom or not but just for information based on my example, that’s what you are seeing. It could very well be a standard repeater and button…just that you would be using the OnClick event, not a custom Attribute as shown below and you would also be casting as “Repeater” not “MyCustomRepeater”.
Short Example (snippets):
First get a good overview of the initial situation/setup that I had:
1:
2: // Here is the custom repeater which resides in MyControl.ascx
3: // This Custom Repeater contains a custom button control (AddToCart) and a <div> to show a message
4:
5: <cc:MyCustomRepeater>
6: <ItemTemplate>
7: <div style="text-align:right">
8: <aa:AddToCart runat="server" Visible="true" id="addToCart" OnAddToCart="AddToCart"
9: CommandArgument="<%#Container.DataItem.Id %>" />
10: </div>
11: <div runat="server" id="ShowSomeMessage" class="Error_small" visible="false">
12: This item has been successfully added to your cart!
13: </div>
14: </ItemTemplate>
15: </cc:MyCustomRepeater>
16:
17: // The code-behind of the control contains an event for the AddToCart button, & related delegate
18: public delegate void AddToCartButtonEventHandler(object sender, int someAbritraryID);
19: public event AddToCartButtonEventHandler OnAddToCart;
20:
21: // Event to handle OnAddToCart
22: protected void AddToCart(object sender, EventArgs e)
23: {
24: // sender is your custom button control
25: AddToCart item = sender as AddToCart;
26: int someAbritraryID = Convert.ToInt32(item.CommandArgument);
27:
28: if (OnAddToCart != null)
29: OnAddToCart(sender, someAbritraryID);
30: }
31:
32: // The code-behind of your .aspx now handles the event & this is where I want to set visibility
33: // property of that div which will show the message
34: // myControl is the ID that you had set for your MyControl.ascx
35:
36: myControl.OnAddToCart += new MyControl.AddToCartButtonEventHandler(myControl_OnAddToCart);
37:
38: void myControl_OnAddToCart(object sender, int someAbritraryID)
39: {
40: // Ok, user has clicked the LinkButton in our user control.
41: // We are handling what we want to do here with this delegate method
42: ...
43:
44: if (something logic here)
45: {
46: // set the div's visible property to true
47: }
48: }
The problem:
So how do you get a reference back to that repeater so you can perform a find control to grab a reference of the div so that you can set its visible property?
The Solution:
Here’s how, at least how I figured it out using the custom button’s naming container:
1: // Get a reference to the repeater that the linkbutton resides in
2: // by first casting the sender and then using that to get a reference to the repeater
3: // through your LinkButton
4:
5: // Since I know the sender is my custom button, we must cast it as that so we can work it
6: AddToCart item = sender as AddToCard;
7:
8: // now we can get the naming container (custom repeater) of the sender (LinkButton)
9: // notice we started with the lowercase myCustomRepeater ID & set it to the casted NamingContainer
10: // myCustomRepeater is the ID, and MyCustomRepeater (uppercase) is the actual type
11: myCustomRepeater ri = (MyCustomRepeater)item.NamingContainer;
12:
13: // nice, now that we have a reference to the custom repeater (ri), we can then do a FindControl
14: // in order to get a reference to that <div> contained within this repeater:
15:
16: // first, create an object of type HtmlGenericControl & perform a find control using the div's ID
17: // be sure to cast the findControl result as an HtmlGenericControl
18: HtmlGenericControl div = (HtmlGenericControl)ri.FindControl("ShowMessage");
19:
20: // now that we have a reference to the div, we manipulate any of its properties
21: // in my case, I needed to set it's visible property to true
22: div.Visible = true;
Now when the user clicks on the LinkButton, my event passes the source to my handler method and I can
cast that sender then use it to get its NamingContainer so I can perform a FindControl in order to get another reference to it's nested control (div).
If you were not using custom controls and standard ASP.NET controls it would look something like this:
1: LinkButton item = sender as LinkButton;
2: myRepeater ri = (Repeater)item.NamingContainer;
3: HtmlGenericControl div = (HtmlGenericControl)ri.FindControl("ShowMessage");
(Note: The code dealing with the custom controls did work fine but did not tried out the last example with plain ordinary ASP.NET controls in this particular instance)
If anyone has a better way to do it, I’m all ears.