This question already has an answer here:
Event won't fire to dynamically added control
(1 answer)
Closed 2 years ago.
I saw lots of thing about this topic but i can't fin a solution.
I add many dropdown list with one event but they are not firing SelectedIndexChanged evet.
Here is drplist creator code:
foreach (var row in cmdSelectCats.ExecuteReader())
{
var id = row["ProductCategoryID"].ToString();
var dropDownStatus = new DropDownList {ID = "DrpStatus-" + id};
dropDownStatus.Items.Add(new ListItem("Aktif", "1"));
dropDownStatus.Items.Add(new ListItem("Pasif", "2"));
dropDownStatus.AutoPostBack = true;
dropDownStatus.SelectedIndexChanged += Status_SelectedIndexChanged;
var tableCell = new TableCell();
tableCell.Controls.Add(dropDownStatus);
dropDownStatus.SelectedValue = row["ProductCategoryStatusID"].ToString();
tableRow.Cells.Add(tableCell);
TblCatList.Rows.Add(tableRow);
}
And ofcourse my Event:
public void Status_SelectedIndexChanged(object sender, EventArgs e)
{
//DO SOMETHING
}
What am i missing?
This is a common issue and it's related to the page life cycle:
Take a look at the following questions:
Click events on Array of buttons
Button array disappears after click event
Dynamically create an ImageButton
Now the basic steps to remember when creating dynamic controls are:
Dynamic controls should be created in the PreInit event when you are not working with a master page, if you are, then create the controls in the Init event
Avoid setting properties that can be changed in each post in these events because when the view state is applied (in a post event) the properties will be overridden
Dynamic controls must be created every time the page is posted, avoid this if(!this.IsPostBack) this.CreatemyDynamicControls();
When you create the controls in the PreInit or Init events, their states will be automatically set in a post event, which means in the LoadComplete event your controls will contain their state back even when you create them again in each post and even when you did not explicitly set their state. Note this behavior is different when you are dealing with controls created at design time, in that case, the event where the state has been set is the Load event
Event subscription should occur before the PageLoadComplete or they will not be raised
Consider the following description from MSDN
If controls are created dynamically at run time or declaratively within templates of data-bound controls, their events are initially not synchronized with those of other controls on the page. For example, for a control that is added at run time, the Init and Load events might occur much later in the page life cycle than the same events for controls created declaratively. Therefore, from the time that they are instantiated, dynamically added controls and controls in templates raise their events one after the other until they have caught up to the event during which it was added to the Controls collection.
The above is not so clear to me, but I have found the following. The following TextBox's are created at design time
protected void Page_PreInit(object sender, EventArgs e)
{
this.txtDesignTextBox1.Text = "From PreInit";
this.txtDesignTextBox1.Text += DateTime.Now.ToString();
}
protected void Page_Init(object sender, EventArgs e)
{
this.txtDesignTextBox2.Text = "From Init";
this.txtDesignTextBox2.Text += DateTime.Now.ToString();
}
protected void Page_Load(object sender, EventArgs e)
{
this.txtDesignTextBox3.Text = "From Load";
this.txtDesignTextBox3.Text += DateTime.Now.ToString();
}
At first sight you might think that in every post all the textboxes are updated with the current date, but this is not the case, since they were created at design time they follow strictly the ASP.Net page life-cycle which means, their state is overriden after the PreInit and Init events, only the txtDesignTextBox3 is updated in every post because its Text property is updated after the view state has been set (in the Load event).
But with dynamic controls the behavior is different, remember the MSDN description:
for a control that is added at run time, the Init and Load events might occur much later in the page life cycle
Consider the following:
protected void Page_PreInit(object sender, EventArgs e)
{
var textBox = new TextBox { Text = "From PreInit", Width = new Unit("100%") };
textBox.Text += DateTime.Now.ToString();
this.myPlaceHolder.Controls.Add(textBox);
}
protected void Page_Init(object sender, EventArgs e)
{
var textBox = new TextBox { Text = "From Init", Width = new Unit("100%") };
textBox.Text += DateTime.Now.ToString();
this.myPlaceHolder.Controls.Add(textBox);
}
protected void Page_Load(object sender, EventArgs e)
{
var textBox = new TextBox { Text = "From Load", Width = new Unit("100%") };
textBox.Text += DateTime.Now.ToString();
this.myPlaceHolder.Controls.Add(textBox);
}
In this case, the controls behave slightly different, in this case, in each post, the controls are never updated not even the controls created in the Load event
The reason is their life-cycle events occurs much later in the page-life cycle which means their state is overridden even after the Load event
To solve this, you can use the LoadComplete event, in this event you can change the state of dynamic controls:
protected void Page_LoadComplete(object sender, EventArgs e)
{
var textBox = new TextBox { Text = "From LoadComplete", Width = new Unit("100%") };
textBox.Text += DateTime.Now.ToString();
this.myPlaceHolder.Controls.Add(textBox);
}
In this case, the state will be updated in each post.
However, take in consideration that you should subscribe to dynamic controls events, before the LoadComplete event or they will not be raised.
... I know I hate this kind of behavior, that's why I love MVC
As a quick reference for controls created at design time: Notice how the LoadViewState method is called after the PreInit and Init events but before the Load event. The Load event is considered stable because in this event you can access the view state of your controls. Also notice that the RaisePostBackEvent method represent the control event that caused the post back, this can be, the SelectedIndexChanged, Click, etc this event is handled after the Load event
For a complete detailed specification read the MSDN Page Life-Cycle documentation
I have usually seen this caused by a page lifecycle problem. If the control is only created when an event is fired, then when your index changed event fires the control doesn't exist to bind it to on the postback.
Example:
MyEvent fires. Drop-down created. Event Handler specified.
Index Changed event triggered. Page reloads. Drop-down not found, cannot fire.
You have to ensure the drop-down is created before .NET attemps to handle the event.
You are missing:
1- Override SaveViewState
2- Override LoadViewState
I provide a sample code for this question. I test it. It's work.
ASPX:
<form id="form1" runat="server">
<asp:Button ID="Button1" runat="server" Text="Button" OnClick="Button1_Click" />
<div id="myDiv" runat="server">
</div>
<asp:Label ID="lblDescription" runat="server"></asp:Label>
</form>
Code Behind:
public partial class Default : System.Web.UI.Page
{
private List<string> values = new List<string>();
protected void Page_Load(object sender, EventArgs e)
{
}
protected override object SaveViewState()
{
object baseState = base.SaveViewState();
object[] allStates = new object[2];
allStates[0] = baseState;
allStates[1] = values;
return allStates;
}
protected override void LoadViewState(object savedState)
{
object[] myState = (object[])savedState;
if (myState[0] != null)
base.LoadViewState(myState[0]);
if (myState[1] != null)
{
values = (List<string>)myState[1];
MyRender();
}
}
protected void Button1_Click(object sender, EventArgs e)
{
for (int i = 0; i < 10; i++)
{
DropDownList ddl = new DropDownList();
ddl.ID = "ClientID" + i;
ddl.Items.Add("Item 1");
ddl.Items.Add("Item 2");
ddl.AutoPostBack = true;
values.Add(ddl.SelectedValue);
myDiv.Controls.Add(ddl);
}
}
private void MyRender()
{
for (int i = 0; i < values.Count; i++)
{
DropDownList ddl = new DropDownList();
ddl.ID = "ClientID" + i;
ddl.Items.Add("Item 1");
ddl.Items.Add("Item 2");
ddl.AutoPostBack = true;
ddl.SelectedIndexChanged += new EventHandler(ddl_SelectedIndexChanged);
myDiv.Controls.Add(ddl);
}
}
void ddl_SelectedIndexChanged(object sender, EventArgs e)
{
lblDescription.Text = ((DropDownList)sender).ID + ": Selected Index Changed";
}
}
Related
Can you help me understand why, when the page is first loaded by the example below, the buttons don't work as intended eg Button 2 doesn't call GetItems(int.Parse("2"), 3); but rather calls GetItems(int.Parse("4"), 3); however after the first postback all the buttons work correctly e.g. Buttonx calls GetItems(int.Parse("x"), 3);
Thanks
protected void Page_Load(object sender, EventArgs e)
{
if(!IsPostBack)
{
GetItems(1, 2); //default values (first time the page is loaded)
}
GenerateButtons(5);
}
private void GenerateButtons(int c)
{
LinkButton[] x = new LinkButton[c];
for(int i=0; i<c;i++)
{
x[i] = new LinkButton();
x[i].Text = (i+1).ToString();
Panel1.Controls.Add(x[i]);
x[i].OnClick += new EventHandler(Button_Click);
}
}
protected void Button_Click(object sender, EventArgs e)
{
Button button = (Button)sender; // Which button was clicked;
GetItems(int.Parse(button.Text), 3); //3 is a constant; first argument is index of button extracted from its caption
}
PS. when I refer to button 1 I have button[0] in mind. button2=button[1] and so on. after postback button1 is correctly attached to the event to trigger GetItems(1,3). Before the postback button1 causes GetItems(3,3) to run. Not as intended
Use the Page_Init so it will work on the first load
protected void Page_Init(object sender, EventArgs e)
{
GenerateButtons(5);
}
Source: https://msdn.microsoft.com/en-us/library/ms178472.aspx
Init Raised after all controls have been initialized and any skin
settings have been applied. The Init event of individual controls
occurs before the Init event of the page. Use this event to read or
initialize control properties
.
When you dynamically create controls you do so in Page_PreInit not Page_Load
protected void Page_PreInit(object sender, EventArgs e)
{
GenerateButtons(5);
}
This article explains and will help you
http://www.robertsindall.co.uk/blog/dynamically-adding-web-controls/
Currently, I am doing a project for students' hostel and now I have to implement some search strategies about students.Here I have to create a button dynamically when the user clicks on the another server button in .aspx page and accordingly I have to create the onclick event handler for the newly created button. The code-snippet that I used is:
protected void btnsearchByName_Click(object sender, EventArgs e)
{
TextBox tbsearchByName = new TextBox();
Button btnsearchName = new Button();
tbsearchByName.Width = 250;
tbsearchByName.ID = "tbsearchByName";
tbsearchByName.Text = "Enter the full name of a student";
btnsearchName.ID = "btnsearchName";
btnsearchName.Text = "Search";
btnsearchName.Click += new EventHandler(this.btnsearchName_Click);
pnlsearchStudents.Controls.Add(tbsearchByName);
pnlsearchStudents.Controls.Add(btnsearchName);
}
protected void btnsearchName_Click(object sender, EventArgs e)
{
lblsearch.Text = "btnsearchName_Click event fired in " + DateTime.Now.ToString();
}
Here, the problem is newly created eventHandler doesnot get fired. I have gone through this site and looked several questions and answers and also gone through the page life-cycle and they all say that the dynamic button should be on Init or Pre_init, but my problem is I have to create it when another button is clicked, how can it be possible?
You need to add the click handler for the button on every postback.
you could look for the button in the search students panel on page load or try the page OnInit() method to add the handler when its created.
Also check here:
Dynamically added ASP.NET button click handler being ignored
and here:
asp.net dynamically button with event handler
and here:
asp:Button Click event not being fired
(all of which give similar suggestions)
Try this http://msdn.microsoft.com/ru-ru/library/system.web.ui.webcontrols.button.command(v=vs.90).aspx
btnsearchName.Command += new CommandEventHandler(this.btnsearchName_Click);
btnsearchName.CommandName = "Click";
You need to recreate the button and attach the event handler every time. For this, create a list of button and save it on session. On page load, go through the List and create the button every time
public Button create_button()
{
btnsearchName.ID = "btnsearchName";
btnsearchName.Text = "Search";
btnsearchName.Click += new EventHandler(this.btnsearchName_Click);
return btnsearchName;
}
public TextBox create_textbox()
{
TextBox tbsearchByName = new TextBox();
Button btnsearchName = new Button();
tbsearchByName.Width = 250;
tbsearchByName.ID = "tbsearchByName";
tbsearchByName.Text = "Enter the full name of a student";
return tbsearchByName;
}
protected void btnsearchByName_Click(object sender, EventArgs e)
{
TextBox tbsearchByName = create_textbox();
Button btnsearchName = create_button();
//add to panels
pnlsearchStudents.Controls.Add(tbsearchByName);
pnlsearchStudents.Controls.Add(btnsearchName);
//add to session
List<Button> lstbutton = Session["btn"] as List<Button>
lstbutton.add(btnsearchName);
//similarly add textbox
//again add to session
Session["btn"] = lstbutton
}
public override page_load(object sender, eventargs e)
{
//fetch from session, the lstButton and TextBox and recreate them
List<Button> lstbutton = Session["btn"] as List<Button>;
foreach(Button b in lstbutton)
pnlsearchStudents.Controls.Add(b);
//similar for textbox
}
I am not sure but may be you have to override the OnInit() method like this.
protected override void OnInit(EventArgs e)
{
base.OnInit(e);
}
You just need to add this code on ready state of jquery code and it will work fine for the dynamic button too
$(document).ready(function(){
$('input#tbsearchByName').click(function(){
// code goes here
});
});
I would like to know why the event is not firing & how to find which checkbox control fired the event.
chkList1 = new CheckBox();
chkList1.Text = row["subj_nme"].ToString();
chkList1.ID = row["subjid"].ToString();
chkList1.Checked = true;
chkList1.Font.Name = "Verdana";
chkList1.Font.Size = 12;
chkList1.AutoPostBack = true;
chkList1.CheckedChanged += new EventHandler(CheckBox_CheckedChanged);
Panel1.Controls.Add(chkList1);
protected void CheckBox_CheckedChanged(object sender, EventArgs e)
{
Label1.Text = "Called";
}
If the events aren't firing, it's likely for one of two reasons:
The controls are recreated too late in the page lifecycle. Try creating the controls during OnInit.
Validation is preventing the postback. To work around this you can set CausesValidation to false on all of the CheckBox controls.
You can find out which control triggered the event using the sender argument.
protected void CheckBox_CheckChanged(object sender, EventArgs e)
{
//write the client id of the control that triggered the event
Response.Write(((CheckBox)sender).ClientID);
}
I'm making dynamic table at Page_LoadComplete, I cant do in at Page_Load becouse data can be changed during events process, so at Page_LoadComplete i make some buttons and want add them EventHandler:
protected void Page_LoadComplete(object sender, EventArgs e) {
btn.Click += new EventHandler(b_Click);
}
But it doesnt work, how to add events to button not at Page_Load?
simple, even not dynamic code:
void b_Click(object sender, EventArgs e) {
Label1.Text = "!!!";
}
protected void Page_Load(object sender, EventArgs e) {
Button1.Click += new EventHandler(b_Click);
}
on Page_Load works fine.
protected void Page_LoadComplete(object sender, EventArgs e) {
Button1.Click += new EventHandler(b_Click);
}
on Page_LoadComplete do nothing.
Ok here's the example:
Given this html snippet:
<body>
<form id="form1" runat="server">
<div>
<asp:Button runat="server" Text="Click Me" OnClick="go_" />
</div>
</form>
</body>
public partial class WebForm1 : System.Web.UI.Page
{
public int ControlCount
{
get { return ViewState["Controls"] == null ? 0 : (int)ViewState["Controls"]; }
set { ViewState.Add("Controls", value); }
}
protected void Page_Load(object sender, EventArgs e)
{
for(int i = 0; i < ControlCount; i++)
{
Button b = new Button();
b.Click += btn_Click;
b.Text = "Hi";
form1.Controls.Add(b);
}
}
void btn_Click(object sender, EventArgs e)
{
((Button)sender).Text = "bye";
}
protected void go_(object sender, EventArgs e)
{
Button btn = new Button();
btn.Text = "Hi";
form1.Controls.Add(btn);
btn.Click += new EventHandler(btn_Click);
ControlCount++;
}
}
Every time you click the first button a new button will be added to the page with the text "Hi", and every time you click a "Hi" button the text for THAT button only will change to "Bye"
This works because I add the controls twice. Once in the event handler of the main button, where I determine that I need a new control, and then AGAIN in OnLoad where I have a new, empty page again, but now I know (via ControlCount) how many controls I added.
The problem is the control doesn't exist on postback (since you created it at run time). Creating the control in Init should solve this, and will allow the event to fire. You can change all of the properties in LoadComplete if you like, but the button needs to exist at that point.
What you're trying will never work because controls that are added dynamically must be REadded every time the page reloads.
Since your control population is based on the data being used in the form, you should put all your control creation logic in a single function, and in your event handlers, maniuplate the data then call your control creation logic function, while in Page Load you would JUST call the control creation function (presuming that you've already persisted the data between calls) so that all the controls that were created the first go around get recreated. Then, once they have been recreated, they can respond to the events that they fired.
I have a problem with a webform.
My Goal: Intially when a page is loading, it has to load every textbox empty. After filling the info and click submit, it has to get submitted(UpdatePaymentInfo())
Problem: Here, When the user fills the info and clicks Submit,it calls onload function even before the submit button and makes all text box empty.
Here is the code:
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
string QueryStringupdatecreditcard1 = Request.QueryString.ToString();
if (String.Equals(QueryStringupdatecreditcard1, "tabID=B"))
{
divTitle.Visible = false;
trmain.Visible = false;
tdOrderSummary.Visible = false;
trCCandBilling.Visible = true;
trtest2.Visible = false;
divUpdatecreditcard.Visible = true;
trusecompaddress.Visible = false;
txtFirstName.Text = "";
txtLastName.Text = "";
txtAddress1.Text = "";
txtAddress2.Text = "";
txtCity.Text = "";
txtZip.Text = "";
txtCardNo.Text = "";
txtVccNumber.Text = "";
trAmountCharged.Visible = false;
}
}
protected void imgbtnSubmit_Click(object sender, ImageClickEventArgs e)
{
try
{
UpdatePaymentInfo();
}
}
Wrap the current contents of your OnLoad method in:
if (!Page.IsPostBack)
{
// Code in here will only be executed when the page is *not* being loaded by a postback
}
This is because, as per the ASP.NET Page Life Cyle, the things that you care about in this instance happen in this order:
Load - During load, if the current request is a postback, control
properties are loaded with information
recovered from view state and control
state.
Postback event handling - If the request is a postback, control event
handlers are called. After that, the
Validate method of all validator
controls is called, which sets the
IsValid property of individual
validator controls and of the page.
So what happens is (somewhat simplified):
You click the image button, triggering the postback.
The data from your form is loaded into your controls.
Your OnLoad method overwrites the values in the controls to clear them.
Your click handler is run, but because of step 3 it sees empty values.
As others have sort-of mentioned, it wouldn't necessarily be a bad thing to refactor your OnLoad method whilst you're doing this. At the moment you seem to have it doing two distinct things:
Clearing the text fields
Setting the visibility of fields
It might be worth separating this into one or two (depending on if the visibility setting and field clearing will be done independently) separate methods and adjusting your OnLoad method so it looks like this:
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
if (!Page.IsInPostBack)
{
SetFieldVisibility();
ClearFields();
}
}
Page_Load always occurs.
See the documentation on the Page Lifecycle
What you need to do is check to see if the Page_Load is being triggered by a Postback.
private void Page_Load(object sender, System.EventArgs e)
{
if(!Page.IsPostBack)
{
///do stuff in here that you want to occur only on the first lad.
}
else
}
// code that you want to execute only if this IS a postback here.
{
}
// do stuff you want to do on Page_Load regardless of postback here.
}
You can use the IsPostBack property of the Page as follows:
protected override void OnLoad(EventArgs e) {
if (!Page.IsPostBack) {
EmptyTextBoxes();
}
}
Have you tried wrapping the form reset code in a check to see if the page is a postback?
if(!Page.IsPostback) {
// Do form reset here
}
You thought about using the IsPostBack page variable?
protected override void OnLoad(EventArgs e)
{
if(!IsPostBack){
//all your logic here.
}
}
if it's the case, you might use a databound control and set it to insert mode