Reputation: 29484
I've got this problem with dynamically created TextBox.
When the TextBox is created in PageLoad, it's TextChanged event was fired.
But when I dynamically delete and recreated the TextBox, the TextChanged was not fired.
This is the code:
.aspx file
<body>
<form id="form1" runat="server">
<div>
<asp:Table ID="Table1" runat="server">
<asp:TableRow>
<asp:TableCell ColumnSpan="2">Fixed content</asp:TableCell>
</asp:TableRow>
</asp:Table>
</form>
</body>
.cs file
public partial class test : System.Web.UI.Page
{
string myText = "a";
protected void Page_Load(object sender, EventArgs e)
{
WriteRows();
}
private void WriteRows()
{
TableRow tr = new TableRow();
TableCell tc = new TableCell();
TextBox txt = new TextBox();
txt.Text = myText;
txt.TextChanged += new EventHandler(txt_TextChanged); // Assign event handler
tc.Controls.Add(txt);
tr.Controls.Add(tc);
tc = new TableCell();
tc.Text = txt.Text;
tr.Controls.Add(tc);
Table1.Controls.AddAt(1, tr);
}
private void txt_TextChanged(object sender, EventArgs e)
{
myText = ((TextBox)sender).Text;
RedrawTable(); // Delete the row (incl. the TextBox) and rewrite it
}
private void RedrawTable()
{
Table1.Controls.RemoveAt(1);
WriteRows();
}
}
Does anyone have a solution so that the event is always fired?
Upvotes: 9
Views: 22313
Reputation: 1
I had same problem, and in my case txt.AutoPostBack = true was what I missed. Default is false, easy to forget.
Upvotes: 0
Reputation: 1
Your answer given below with entire code:
string myText = "a";
protected void Page_Load(object sender, EventArgs e)
{
WriteRows();
}
private void WriteRows()
{
TableRow tr = new TableRow();
TableCell tc = new TableCell();
TextBox txt = new TextBox();
txt.Text = myText;
txt.ID = "txt1";
txt.TextChanged += new EventHandler(txt_TextChanged); // Assign event handler
txt.AutoPostBack = true;
tc.Controls.Add(txt);
tr.Controls.Add(tc);
tc = new TableCell();
tc.Text = txt.Text;
tr.Controls.Add(tc);
Table1.Controls.AddAt(0,tr);
}
private void txt_TextChanged(object sender, EventArgs e)
{
myText = ((TextBox)sender).Text;
RedrawTable(); // Delete the row (incl. the TextBox) and rewrite it
}
private void RedrawTable()
{
Table1.Controls.RemoveAt(0);
WriteRows();
}
Upvotes: 0
Reputation: 939
You will be required to just assign an ID property with the Textbox. It should resolve your problem.
Upvotes: 0
Reputation: 1739
Re-create dynamically created controls in Page_Init. You won't have access to the viewstate data of a control if you recreate it in Page_Load (viewstate is loaded in PreLoad which happens before Page_Load).
Also, don't forget to assign an ID to the control.
Upvotes: 2
Reputation: 50395
Event handling is done by ASP.NET by matching up control's ID & the request parameters. In your case, the TextBox created during txtTextChanged() will have an auto ID because you don't specify any explicit ID. That ID will be posted back during the text changed event.
After page load event, ASP.NET will try to find a control with such ID to fire the event for it. Obviously ASP.NET won't be able to find the match because the TextBox created during Page_Load() is different and would have different ID.
To solve this: specify an explicit ID for your textbox:
TextBox txt = new TextBox();
txt.Text = myText;
txt.ID = "txtBox";
Upvotes: 12
Reputation: 37655
I'm once again reminded why I avoid asp - to me it seems like one level of abstraction too many. But by analogy with javascript, is it possible you're ending up with more than one handler on the event?
Upvotes: 0
Reputation: 3491
for a postback event to fire, the control that should fire the event needs to be available with the same id and the same data on the postback lifecycle.
If you have static controls (defined in your aspx/ascx/master) and viewstate turned on, then they will be recreated automagically.
If you don't want to use viewstate, or use dynamic controls, you need to databind controls on each page_load, so that the controls are up and running in time for events to fire (happens after Page_load)
if you change the ID of a parent control, or page, you might accidentally throw off the viewstate autobind, as the control IDs contains ancestors IDs. I think you should be safe doing that, so long as you do it in Page_Init (before viewstate is set up)
Upvotes: 2
Reputation: 1795
...as another suggestion, isn't binding events after Page_Load too late? and therefore they won't be fired on the postback. maybe something to check out..
Upvotes: 0
Reputation: 37655
When I was researching this issue, it was in the context of Dynamic Menus, and there are a bunch of Google responses that, together, got me through it (because it's a common enough requirement, I guess.) I don't have a summary of the answer, but it might be a helpful place to start (i.e. google for Dynamic Menus .NET). There are several questions here on this site too.
Upvotes: 0
Reputation: 11478
I had a similar problem. I think the issue is that dynamically created controls are not kept in view state and don't survive a postback. Here is a comment ripped from my code that describes the solution that I came up with (it may not be the only one, but it worked for me).
This page is used to define a grid dynamically. The user clicks checkboxes to indicate which fields to include on the grid. The logic of this page does two essential things:
(1) It maintains the GridDefinition object that is kept in ViewState. (2) It reconstructs the programatically added controls (essentially everything in the table object) from the GridDefinition in ViewState on each postback. The dynamically added controls are NOT recreated on the postback from ViewState. Indeed, I found that if you don't recreate the controls, their events won't fire. Apparently:
"The process that matches controls to posted values occurs
after page_load completes, so it has to occur just like this
if you are to use this way."
When I get a control event indicating some change to the data, I have to reflect that change in the GridDefinition object stored in ViewState. That way, on the NEXT postback, the control can be recreated properly (e.g. a text box indicating the header text for a grid column).
Upvotes: 1