3

IDE: Visual Studio 2010

.net version: 3.5

OS: Windows 7

Web Server: Visual Studio 2010 Development Server

Below is some asp.net C# code. This is the code behind on an otherwise blank, out of the box, web form. What I don't understand is why the testClick event does not fire when I click the button, but if I comment out the following line so that the button is rendered on postback it does fire.

if (!IsPostBack)

Obviously it has to do with page lifecycle and how/when controls are rendered, but I don't understand. When the page posts back, isn't the btnTest button a new instance of btnTest? Why does the page care if it actually exists after postback? The event handler exists. It seems as if that should be the important thing. I'm hoping someone can break down the order that things are happening and explain this (obviously correct and intentional) behavior to me.

Thank you for reading.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;

public partial class _Default : System.Web.UI.Page 
{
    Button btnTest = new Button();
    protected void Page_Load(object sender, EventArgs e)
    {
        if (!IsPostBack)
        {
            btnTest.Text = "TEST";
            this.Form.Controls.Add(btnTest);
            btnTest.Click += new EventHandler(testClick);
        }
    }

    protected void testClick(Object sender, EventArgs e)
    {
        Response.Write("Test button event has been handled");
    }
}

Okay, so now I am COMPLETELY confused! In the following code btnTest and btnTest2 are not the same button. When the page posts back it fires the event handler for btnTest2 as if btnTest2 were clicked, but btnTest2 was NOT clicked. btnTest was. I do not understand this behavior. I have read the page lifecycle article at https://msdn.microsoft.com/en-us/library/ms178472(v=vs.80).aspx as suggested, but I don't think it adequately explains this behavior.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;

public partial class _Default : System.Web.UI.Page 
{
    protected void Page_Load(object sender, EventArgs e)
    {
        if (!IsPostBack)
        {
            Button btnTest = new Button();
            btnTest.Text = "TEST";
            this.Form.Controls.Add(btnTest);
            btnTest.Click += new EventHandler(testClick);
        }       

        if (IsPostBack)
        {
            Button btnTest2 = new Button();
            btnTest2.Text = "TEST";
            this.Form.Controls.Add(btnTest2);
            btnTest2.Click += new EventHandler(testClick_Postback);
        }        
    }

    protected void testClick(Object sender, EventArgs e)
    {
        Response.Write("Test button event has been handled by original handler");
    }

    protected void testClick_Postback(Object sender, EventArgs e)
    {
        Response.Write("Test button event was handled by new handler assigned on postback");
    }
}
1
  • You click the button, the postback happens and then it looks at the click events, and there are none. Thus the handler doesn't fire. Commented Jun 2, 2015 at 15:45

2 Answers 2

4

Because that code is only executed if the request is not a post-back, so the control is not created and the event handler is not attached. Either put the control (and event handler) in the markup or add/attach it on every request, not just non-post-backs.

Controls and their events do not persist across requests - they are either created from the markup or in the code behind. When you do a post-back, the control does not exists on the page and thus there's no event to fire.

3

By dynamically wiring up the event handler in the Page_Load, the event handler will only be subscribed if IsPostBack is false, viz on the first time that the page is rendered, before postbacks (e.g. before Buttons et al are clicked).

Unlike other control properties (like .Text, .Color etc) on the button, event handlers are not serializable across ViewState and thus must be wired up irrespective of PostBack or not.

For design time controls, it is best to leave the event handler wire up in the actual .ASPX button control definition.

However, since you've created the Button dynamically, you have no other option but to wire up the handler each time.

2
  • Thank you. This is a very stripped down SSCCE of a class I'm writing whereby I'm trying to create an asp.net equivalent of a C# MessageBox that wraps a panel control and displays a configurable message, which will then fire an event when the OK button is pressed. I had it coded such that it populated __eventTarget and __eventArgument and handled the click on page load, but I was hoping to configure it so that it would disappear and fire a configurable delegate on postback without having to re-render the panel control. I'm beginning to think my first solution may be the way to go.
    – Camenwolf
    Commented Jun 2, 2015 at 15:57
  • What is confusing is it seemed that the EventHandler delegate should be passed in the viewstate on postback. Like "Hey, a button has been pressed with this handler, so fired it when you post back." regardless of whether the button is actually rendered or not. Isn't the dynamic button here a completely new instance of the button object when the page posts back? Doesn't it discard the old one in garbage collection?
    – Camenwolf
    Commented Jun 2, 2015 at 16:05

Not the answer you're looking for? Browse other questions tagged or ask your own question.