Dynamic creation of Button OK but its event handler NOT executed? - asp.net

I have following simple controls on a page
WebForm1.aspx
<asp:Panel ID="Panel1" runat="server">
</asp:Panel>
<br />
<asp:Label ID="lblContent" runat="server" ></asp:Label>
Some code behind in WebForm1.aspx.cs :
protected void Page_Load(object sender, EventArgs e)
{
Button btn = new Button();
btn.ID = "btnTest";
btn.Text = "I was dynamically created";
btn.Click += new EventHandler(btnTest_Click);
Panel1.Controls.Add(btn);
}
void btnTest_Click(object sender, EventArgs e)
{
lblContent.Text = "btnTest_Click: " + DateTime.Now.ToString();
}
In short, when I dynamically create a Button (btnTest) in the Page_Load event and assign event handler btnTest_Click to the button. Click event then, when loading the page I see btnTest appearing and when clicking on it the event handler btnTest_Click is invoked. OK, No problem.
I have a problem though when I try following scenario... first, I add a button to the page in designer mode.
<asp:Panel ID="Panel1" runat="server">
</asp:Panel>
<asp:Button ID="btnCreateDynamically" runat="server"
Text="Create Button Dynamically"
onclick="btnCreateDynamically_Click" />
<br />
<asp:Label ID="lblContent" runat="server" ></asp:Label>
I move the code from Page_Load to the button event handler of btnCreateDynamically as follows
protected void btnCreateDynamically_Click(object sender, EventArgs e)
{
Button btn = new Button();
btn.ID = "btnTest";
btn.Text = "I was dynamically created";
btn.Click += new EventHandler(btnTest_Click);
Panel1.Controls.Add(btn);
}
When running the WebApp now and clicking on btnCreateDynamically, btnTest is created but when I click on btnTest its event handler is NOT invoked ???
Why not?
How can I make this work?

You should add the dynamic controls in the Page's Init event handler so that the ViewState and Events are triggered appropriately.
Try doing this:
protected void Page_Init(object sender, EventArgs e)
{
Button btn = new Button();
btn.ID = "btnTest";
btn.Text = "I was dynamically created";
btn.Click += new EventHandler(btnTest_Click);
Panel1.Controls.Add(btn);
}

You need to re-create dynamic control on each postback, see my previous answer to a similar question here

Related

Disable postback of a dynamically created button asp.net

This is my Page1.aspx code:
<asp:Content ID="Content1" ContentPlaceHolderID="MainContent" Runat="Server">
<asp:Panel ID="Panel1" runat="server">
<asp:Button ID="Button1" runat="server" Text="Button" OnClick="Button1_Click" />
</asp:Panel>
</asp:Content>
This is my Page1.aspx.cs code
public partial class Page1 : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
if (IsPostBack == true)
{
btn_Click(sender, e);
}
}
protected void Button1_Click(object sender, EventArgs e)
{
Button btn = new Button();
btn.Text = "Dynamic button";
btn.Click += btn_Click;
Panel1.Controls.Add(btn);
}
void btn_Click(object sender, EventArgs e)
{
Response.Redirect("../Page2");
}
}
From this code, when "Button1" is clicked it should create a new button "btn" and when "btn" is clicked, it should go to the url in its click function (i.e. btn_Click()). But when I click "Button1" it does not execute "Button1_Click()" but "btn_Click()". What should I do??
if (IsPostBack == true)
can become
if (IsPostBack)
Then
Response.Redirect("../Page2");
can become
Response.Redirect("~/Page2");
In the aspx check you have:
<asp:Button runat="server" ID="Button1" OnClick="Button1_Click"></asp:Button>
Moreover you can bind click in code behind (eg OnLoad):
Button1.Click += Button1_Click;
and also unbind:
Button1.Click -= Button1_Click;

C# - Event handler for dynamic buttons

I have a textbox and submit button created using the design mode.
When the submit button is pressed, it will retrieve the user input from the textbox and then make a query to my database.
It will then display a list of dynamic buttons according to the information retrieved from my database.
However, the event handler for the buttons does not fire when clicked. I guess my problem is the postback but I cannot create those buttons in page_load etc. because I need to get the user input (from the textbox when submit button is pressed) before i can load the buttons.
How can i solve this problem?
Thank you.
Edit (codes):
protected void subBtn_Click(object sender, EventArgs e)
{
//database setup codes
.......
while (reader.Read())
{
Button detailsBtn = new Button();
detailsBtn.Text = reader["fName"].ToString();
//doesn't fire
detailsBtn.Click += new EventHandler(detailsBtn_Click);
memPanel.Controls.Add(detailsBtn);
}
}
Main problem is Postback regenerate dynamic controls on each postback if those controls does not exists.
For quick demo see this code
ASPX CODE
<form id="form1" runat="server">
<asp:Button ID="Button1" runat="server" Text="Button" onclick="Button1_Click" />
<asp:Panel ID="pnl" runat="server"></asp:Panel>
</form>
ASPX.CS CODE
protected void Page_Load(object sender, EventArgs e)
{
if(IsPostBack)
{
generate();
}
}
public void generate()
{
if (!pnl.HasControls())
{
for (int i = 0; i < 4; i++)
{
Button detailsBtn = new Button();
detailsBtn.Text = "fName" + i.ToString();
detailsBtn.ID = i.ToString();
detailsBtn.Click += new EventHandler(detailsBtn_Click);
pnl.Controls.Add(detailsBtn);
}
}
}
protected void Button1_Click(object sender, EventArgs e)
{
generate();
}
protected void detailsBtn_Click(object sender, EventArgs e)
{
}
Sound to me like you could easily refactor your page to use a simple <asp:Repeater runat="server" ..></asp:Repeater> instead of dynamically adding controls to a Panel.
Here is a very simple complete sample:
RepeaterTest.aspx
<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="Server">
<asp:TextBox ID="theTextBox" runat="server"></asp:TextBox>
<asp:Button ID="theButton" runat="server" OnClick="theButton_Click" Text="Click me" />
<asp:Repeater ID="test" runat="server">
<ItemTemplate>
<asp:Button ID="theRepeaterButton" runat="server" Text='<%# Eval("fName") %>' OnClick="theRepeaterButton_Click" />
</ItemTemplate>
</asp:Repeater>
</asp:Content>
RepeaterTest.aspx.cs
public partial class RepeaterTest : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
}
protected void theButton_Click(object sender, EventArgs e)
{
string filter = theTextBox.Text;
// below row simulates fetching data using the filter text in the text box
var data = Enumerable.Range(0, 20).Select(i => new { fName = filter + " " + i });
test.DataSource = data;
test.DataBind();
}
protected void theRepeaterButton_Click(object sender, EventArgs e)
{
var button = (Button)sender;
// do something here based on text/commandname/commandargument etc of the button
}
}

Adding dynamic buttons to updatepanels and tieing in onclick event ASP.net Webforms

I got a query regarding adding dynamic buttons with dynamic onclick events on a set of updatepanels.
I've simplified the scenario as the code I have so far is way too long and tied up..I've created a test page with 3 update panels.
In terms of the actual page the first updatepanel will be for the filters which will in turn update the second update panel. 2nd update panel will consist of all the results, depending on filters..this will be a table of buttons.
On the click of any of these buttons on the second update panel, depending on the ID of the button the results will be generated in the last update panel.
The problem I'm facing is tieing in the button click event when the buttons are created.
When I create the button from the onclick from the first update panel, it adds it to the placeholder but the click event does not fire at all.
Here is some code from my testing page.
test.aspx
<asp:ScriptManager ID="ScriptManager1" runat="server">
</asp:ScriptManager>
<asp:UpdatePanel ID="UpdatePanel1" runat="server">
<ContentTemplate>
<asp:Button ID="Button1" runat="server" Text="Button" onclick="Button1_Click" />
</ContentTemplate>
</asp:UpdatePanel>
<asp:UpdatePanel ID="UpdatePanel2" runat="server" ChildrenAsTriggers="False"
UpdateMode="Conditional">
<ContentTemplate>
<asp:PlaceHolder id="ph2" runat="server"></asp:PlaceHolder>
</ContentTemplate>
</asp:UpdatePanel>
<asp:UpdatePanel ID="UpdatePanel3" runat="server" UpdateMode="Conditional">
<ContentTemplate>
<asp:PlaceHolder id="ph3" runat="server"></asp:PlaceHolder>
</ContentTemplate>
</asp:UpdatePanel>
Codebehind:
public partial class test : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
}
protected void Button1_Click(object sender, EventArgs e)
{
Button up2button = new Button();
up2button.ID = "up2button";
ph2.Controls.Add(up2button);
up2button.Click += new EventHandler(up2button_Click); // Not being registered?
AsyncPostBackTrigger trigger1 = new AsyncPostBackTrigger();
trigger1.ControlID = "up2button";
trigger1.EventName = "Click";
UpdatePanel2.Triggers.Add(trigger1);
ScriptManager1.RegisterAsyncPostBackControl(up2button);
UpdatePanel2.Update();
}
protected void up2button_Click(object sender, EventArgs e) { //and not being fired
Button up3button = new Button();
up3button.ID = "up3button";
up3button.Click += new EventHandler(up3button_click);
ph3.Controls.Add(up3button);
AsyncPostBackTrigger trigger1 = new AsyncPostBackTrigger();
trigger1.ControlID = "up3button";
trigger1.EventName = "Click";
UpdatePanel3.Triggers.Add(trigger1);
UpdatePanel3.Update();
}
protected void up3button_click(object sender, EventArgs e) {
}
}
Thankyou for your time.
here's a quick sample, I find on the internet:
I've used a placeholder to hold the dynamically created controls - the button and textboxes on that button's click event.
and the code:
protected void Page_Load(object sender, EventArgs e)
{
if (IsPostBack)
{
if (ViewState["Add"] != null)
{
Button add = new Button();
add.Text = "Add";
add.Click += new EventHandler(add_Click);
PlaceHolder1.Controls.Add(add);
}
if (ViewState["textboxes"] != null)
{
int count = 0;
count = (int)ViewState["textboxes"];
for (int i = 0; i < count; i++)
{
textbox textbox_foradd = new TextBox();
textbox_foradd.ID = "textadd" + (i + 1).ToString();
PlaceHolder1.Controls.Add(textbox_foradd);
}
}
}
}
void add_Click(object sender, EventArgs e)
{
int count = 1;
if (ViewState["textboxes"] != null)
{
count += Convert.ToInt32(ViewState["textboxes"]);
}
TextBox textbox_foradd = new TextBox();
textbox_foradd.ID = "textadd" + count.ToString();
PlaceHolder1.Controls.Add(textbox_foradd);
ViewState["textboxes"] = count;
}
protected void Button1_Click(object sender, EventArgs e)
{
Button add = new Button();
add.Text = "Add";
PlaceHolder1.Controls.Add(add);
ViewState["Add"] = 1;
}
Also, you need to give unique ID to each control in case you add multiple of the same control.
Ex:
Add button with id 'ButtonA'
Add another button with id 'ButtonA'
will fail, after the postback your buttons will trigger the event properly, but the action will not do a proper refresh.
Making it looks like it is not refreshing anymore.
Instead generate a unique ID for each control you add dynamically (and save those IDs).
In the postback, recreate those controls and reassign the IDs properly.
Only then will the UI refresh properly.

e.CommandArgument for asp button is not working

I am developing a asp.net application using C#.
I created an .aspx page and placed four buttons on different locations on the page.
On server side, I want to use just one click event for all four buttons.
Here is my code:
aspx page
<asp:Button ID="Button1" runat="server" CommandArgument="Button1" onClick = "allbuttons_Click" />
<asp:Button ID="Button2" runat="server" CommandArgument="Button2" onClick = "allbuttons_Click" />
<asp:Button ID="Button3" runat="server" CommandArgument="Button3" onClick = "allbuttons_Click" />
<asp:Button ID="Button4" runat="server" CommandArgument="Button4" onClick = "allbuttons_Click" />
cs page
protected void allbuttons_Click(object sender, EventArgs e)
{
//Here i want to know which button is pressed
//e.CommandArgument gives an error
}
#Tejs is correct in his comment, looks like you want something like this:
protected void allbuttons_Click(object sender, EventArgs e)
{
var argument = ((Button)sender).CommandArgument;
}
Use
OnCommand =
and
protected void allbuttons_Click(object sender, CommandEventArgs e) { }
Actually you don't need to pass the CommandArgument at all to know which button you pressed. You can get the ID of the button like below:
string id = ((Button)sender).ID;
You can assign command-text to your buttons as follows:
protected void allbuttons_Click(Object sender, CommandEventArgs e) {
switch(e.CommandName) {
case "Button1":
Message.Text = "You clicked the First button";
break;
case "Button2":
Message.Text = "You clicked the Second button";
break;
case "Button3":
Message.Text = "You clicked Third button";
break;
case "Button4":
Message.Text ="You clicked Fourth button";
break;
}
}

ASP.NET Timer Event

protected void SubmitButtonClicked(object sender, EventArgs e)
{
System.Timers.Timer timer = new System.Timers.Timer();
---
---
//line 1
get_datasource();
String message = "submitted.";
ScriptManager.RegisterStartupScript(this.Page, this.GetType(), "popupAlert", "popupAlert(' " + message + " ');", true);
timer.Interval = 30000;
timer.Elapsed += new ElapsedEventHandler(timer_tick);
// Only raise the event the first time Interval elapses.
timer.AutoReset = false;
timer.Enabled = true;
}
protected void timer_tick(object sender, EventArgs e)
{
//line 2
get_datasource();
GridView2.DataBind();
}
The problem is with the data in the grid view that is being displayed... since when get_datasource which is after line 1 is called the updated data is displayed in the grid view since it is a postback event but when the timer event handler is calling the timer_tick event the get_datasource function is called but after that the updated data is not visible in the grid view. It is nnot getting updated since the timer_tick is not a post back event
The server-side timer as you have implemented it, will not work for what you are trying to achieve.
If you wrap both the timer and gridview in a updatepanel, the timer will trigger a postback everytime the tick event fires and you be able to update the data.
Heres a great blog post to get you going: http://mattberseth.com/blog/2007/08/using_the_ajax_timer_control_a.html
<asp:UpdatePanel runat="server" UpdateMode="Conditional">
<ContentTemplate>
<asp:GridView ID="GridView2" runat="server">
</asp:GridView>
<asp:Timer id="Timer1" runat="server" Interval="30000" OnTick="Timer_Tick" Enabled="false" />
<asp:Button ID="Button1" runat="server" Text="Update" OnClick="SubmitButtonClicked" />
</ContentTemplate>
</asp:UpdatePanel>
Server-side code:
private void Timer_Tick(object sender, EventArgs args)
{
get_datasource();
GridView2.DataBind();
Timer1.Enabled = false;
}
protected void SubmitButtonClicked(object sender, EventArgs e)
{
String message = "submitted.";
ScriptManager.RegisterStartupScript(this.Page, this.GetType(), "popupAlert", "popupAlert(' " + message + " ');", true);
get_datasource();
GridView2.DataBind();
Timer1.Enabled = true;
}
You cannot use a timer like that. While ASP.NET tries to hide the request/response cycle of HTTP, the cycle is still there so you cannot just do whatever you like in your postback: you still need to understand that a HTML response is being sent back in response to a HTTP request.
Is there any particular reason why you're trying to use a timer like this? It doesn't seem to make sense to me. What is it that you're trying to achieve?

Resources