Reputation: 798
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");
}
}
Upvotes: 3
Views: 1879
Reputation: 107237
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.
Upvotes: 3
Reputation: 152491
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.
Upvotes: 4