1
votes

Essentially I have a placeholder added to the page dynamically on page load.

Then I have a composite control that is added to the placeholder and displayed during runtime for specific page events. The composite control has a button. I have a public eventhandler for the button available in the composite control, but don't actually have direct access to this eventhandler in the page code.

To display the control, I would make the following call for example:

MyControl.Create(args, new EventHandler(OnClick)); 

Then on the page I would have protected void OnClick(object o, EventArgs args) {}

Of course when I call create() I wire up my eventhandler to the composite control's button click event. So far so good. With the button wired, the button click posts back to the control as expected. However, the event never makes it back to the page's event handler.

I realize the problem is occurring on postback. Yet, attempting to wire the button on init, load or createchildcontrols all fail to keep the wiring in place so the event can be handled on the page. What I would like, is the ability to pass the eventhandler to the composite control during runtime, and for the composite control to send the event correctly back to the page on postback.

Interestingly, if I call OnBubble with custom eventargs I can catch the bubbled event on the page. But the problem is that my placeholder is on the page, so when I attempt to call MyControl.Create() in a UserControl, for example, the bubble goes to the page and not to the UserControl (as expected). Hence, the reason I prefer to declare the eventhandler instead of overriding OnBubble (UserControls and other controls that declare MyControl would essentially render it useless for button click events).

I'm hoping someone has some insight into the problem. It seems like an interesting problem, but perhaps there is no solution outside of declaring the control explicitly on the page, and directly wiring up the event either in the markup or on pageload. I would consider having the button make an asynchronous callback, but would prefer to use standard ASP.NET event handling if possible.

Thanks!

To add clarification: the MyControl.Create() call actually generates an event that calls the Composite Control's Create() method. this is all well and good, but it is worth noting that the MyControl.Create() method does not have direct access to the control. This should make sense because the the control is added to the page onload on not in markup.

More Code:

MyControl : CompositeControl 
{
     public event EventHandler Click;

     //I have a create method
     void Create(args, EventHandler click)
     {
          this.Click = click;
          //other processing
     }

     //then the button is wired up. I've tried in OnInit(), OnLoad()
     void CreateChildControls()
     {
           MyButton.OnClick += Click;
     }

     //if I wire up the button to a default handler I can check if
       Click is not null and send the click event onto the next handler 
     //this is where the bubble event works, but the wiring fails
} 

Edit: My attempt to store the eventhandler in the Session and wire up the button on postback was successful. I don't consider this good practice, and I don't think it actually serves my purpose. For example, in this case the event on the page executes as expected, but with non-standard page behavior. For example, Response.Redirect() throws an exception. This should make sense because the eventhandler has probably lost state information during the postback. A couple of thoughts: 1. Is it possible that I could create a custom bubble event that is somehow related to this control? This seems plausible, but again the problem of the page postback leaves me with the same problem of where the bubble should go. So, when I call create(), is it possible that I can automagically register the UserControl as the destination for the bubble? It seems difficult. 2. Is there some point in the page lifecycle where I can re-wire the event on the UserControl declared eventhandler so that the delegate is called correctly on postback? This seems to be what I am missing. The eventhandler is created on a postback, but is lost because it is not re-created in the UserControl during OnClick. I don't want the UserControl to have to explicitly re-create the thing, but want the child control to re-create it for the UserControl. It sounds like a simple request, but with the UserControl out of the loop, I may be asking for the impossible.

4
Can you post some more code where you actually wire up the handler?user134706
I'm pretty sure you leak memory by storing the event handler in there ;)user134706

4 Answers

1
votes

You have not specifically mention at which point of the page lifecycle do you create and add those controls. For the postback to work, all the creation(and wiring) and 're-creation' has to be done before page_load event.

Do it at page_init and the viewstate mechanism should take over the postback values if the IDs are the same.

I've come across another method here though: http://www.codeproject.com/KB/viewstate/retainingstate.aspx

0
votes

What is your motivation for dynamically inserting the control into a placeholder? A page doesn't really exist between requests, so any controls that are dynamically inserted don't survive. You'd basically have to fake it.

One option you may want to consider is writing a custom control that has different rendering modes but has a consistent event interface. Another is to use an ASP.NET MultiView control, which will only render the visible view in the HTML but still maintains the event handlers in the invisible Views.

0
votes

Okay, correct me if I'm wrong, your Create() method actually instantiates and sets your inner control to a known state; I see you already have a reference to the button, then why do you need an extra Click event at this point?

When you call Create() you'll initialize the control and its button, then, when you know the button is there, hook up your event handler passing that parameter you got there.

MyControl : CompositeControl
{
    void Create(args, EventHandler click)
    {
        // init & set up your control

        // other processing

        MyButton.OnClick += click;
    }
}
0
votes

You should always put the same ID to dynamically created controls, if you fail to it sometimes control events are not raised,

hope this help.