Generic event handler not firing from dynamic buttons - c#

I have a bunch of buttons being dynamically created and setting its click event to an event handler...When I run it they handler in never firing, I've stepped through the code and nothing seems out of the ordinary but it just won't fire.
Here is a snippet of the code where the button is being created..
for (cellCtr = 1; cellCtr <= 9; cellCtr++)
{
Button button = new Button();
HyperLink link = new HyperLink();
TableCell tCell = new TableCell();
if (rowCtr == rN)
break;
string myStr = daccess.dsSubjects.Tables[0].Rows[rowCtr]["SubjectName"].ToString();
int myID = Convert.ToInt32(daccess.dsSubjects.Tables[0].Rows[rowCtr]["SubjectID"].ToString());
button.ID = Convert.ToString(myID);
button.Text = myStr;
button.CssClass = "btn btn-primary btn-sm";
button.Click += ButtonSubjectClick;
tCell.Controls.Add(button);
tRow.Cells.Add(tCell);
rowCtr++;
if (cellCtr == rN)
{
rowCtr = rowCtr - 1;
break;
}
}
and here is the handler that's it suppose to call...
void ButtonSubjectClick(object sender, EventArgs e)
{
Button button = (Button)sender;
daccess.DeleteSubjects(Int32.Parse(button.ID.ToString()));
button.CssClass = "btn-active";
}
When its ran, the source looks like this
<input type="submit" name="38" value="Math" id="38" class="btn btn-primary btn-sm" />

This code works for me:
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
// do something if needed
}
// outside of postback, you need to add it each time
Button button = new Button();
button.ID = "btn1";
button.Text = "clicky me";
button.Click += new EventHandler(ButtonSubjectClick);
pnl.Controls.Add(button);
}
void ButtonSubjectClick(object sender, EventArgs e)
{
Button button = (Button)sender;
button.Text = "clicked me";
}
I believe it's a question about how are you adding your button to the page. I'm adding my button at each postback and it is thus registered by the server.
If you are adding your buttons in another event then you could use viewstate or session variables, store some kind of a flag to create the button and then check for this flag in each postback.
Edit, for the sake of clarity, pnl is a Panel on my page:
<form id="form1" runat="server">
<div>
<asp:Panel ID="pnl" runat="server"></asp:Panel>
</div>
</form>

Related

Dynamically created button after page load realoads the page but does not fire the

I have a problem with asp.net event system.
As the page is being loaded for the first time, a DropDownList is being populated and that's it. On the list SelectedIndexChange the page does a page postback and loads some more info, dynamically creating buttons for it based on some data taken out from the DB.
And at this point all works as expected, the CustomDivs are created and displayed correctly. The problems happens when i click on one of the dynamically created buttons, the page does the postback, goes trouhg the page load but never enters the method of the button that was clicked.
Looking around in the internet i read something about event handlers must be created in the Page_Load method to registered. So i even modified the code behind so that the CaricaPostazioni() method would be fired in the Page_Load, but that did not work. I also tried some other stuff like AutoPostBack property or UseSubmitBheaviour or CausesValidation but nothing seems to work as expected.
I should say that this page is a content page of master page that does absolutely nothing in it's Page_Load()
Any one can help me in this matter? Thank you very much!
Here is the code behind of assegnapostazione.aspx
using Industry4_camerana_gruppo1.App_Code;
using Industry4_camerana_gruppo1.App_Code.Dao;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
namespace Industry4_camerana_gruppo1 {
public partial class assegnapostazione : System.Web.UI.Page {
static List Macchinisti = null;
protected void Page_Load(object sender, EventArgs e) {
if (Macchinisti == null) {
Macchinisti = new daoUtente().GetByRuolo("macchinista");
drp_Macchinisti.Items.Add(new ListItem("Seleziona...", "-1"));
foreach (Utente U in Macchinisti) {
drp_Macchinisti.Items.Add(new ListItem(U.Username, U.ID.ToString()));
}
}
}
public void CaricaPostazioni() {
//if (drp_Macchinisti.SelectedValue == "-1") return;
int IDUtente = Convert.ToInt32(drp_Macchinisti.SelectedItem.Value);
List Postazioni = new daoPostazioni().GetAll();
Dictionary Relazioni = new daoPostazioni().GetUtentePostazioni(IDUtente);
if (Postazioni != null) {
Panel row = new Panel();
row.CssClass = "row";
int i = 0;
foreach (Postazione p in Postazioni) {
if (i % 4 == 0) {
pnl_Postazioni.Controls.Add(row);
row = new Panel();
row.CssClass = "row";
}
if (Relazioni.ContainsKey(p.ID)) {
row.Controls.Add(CustomDiv(p, IDUtente, true));
} else {
row.Controls.Add(CustomDiv(p, IDUtente, false));
}
i++;
}
pnl_Postazioni.Controls.Add(row);
}
}
public Panel CustomDiv(Postazione P, int IDUtente, bool Assegnato) {
//
//
//
//
// Foratura
//
//
//
Panel wrapper = new Panel();
wrapper.CssClass = "col";
Panel card = new Panel();
card.CssClass = "card text-center postazione form-group";
Image img = new Image();
img.CssClass = "mx-auto d-block width-70";
img.ID = "btn_" + P.ID;
img.ImageUrl = "~/imgs/ic" + P.Tipo + ".png";
Panel cardTitle = new Panel();
cardTitle.CssClass = "card-title";
Label title = new Label();
title.Text = P.Tipo.ToUpper() + " - " + P.Tag;
Button btn = new Button();
//btn.ID = "btn_" + P.ID + IDUtente;
btn.Attributes.Add("PID", P.ID.ToString());
btn.Attributes.Add("UID", IDUtente.ToString());
//btn.UseSubmitBehavior = true;
if (Assegnato) {
btn.Click += new EventHandler(btn_Rimuovi_Click);
//btn.Click += delegate {
// btn_Rimuovi_Click(btn, null);
//};
btn.CssClass = "btn btn-warning mx-auto form-control";
btn.Text = "Rimuovi";
} else {
btn.Click += new EventHandler(btn_Assegna_Click);
//btn.Click += delegate {
// btn_Assegna_Click(btn, null);
//};
btn.CssClass = "btn btn-success mx-auto form-control";
btn.Text = "Assegna";
}
card.Controls.Add(img);
cardTitle.Controls.Add(title);
card.Controls.Add(cardTitle);
card.Controls.Add(btn);
wrapper.Controls.Add(card);
return wrapper;
}
protected void drp_Macchinisti_SelectedIndexChanged(object sender, EventArgs e) {
CaricaPostazioni();
}
protected void btn_Rimuovi_Click(object sender, EventArgs e) {
Button btn = (Button)sender;
new daoPostazioni().AddRelazione(Convert.ToInt32(btn.Attributes["UID"]), Convert.ToInt32(btn.Attributes["PID"]));
}
protected void btn_Assegna_Click(object sender, EventArgs e) {
Button btn = (Button)sender;
new daoPostazioni().DeleteRelazione(Convert.ToInt32(btn.Attributes["UID"]), Convert.ToInt32(btn.Attributes["PID"]));
}
}
}
Well, I have an answer for you but I don't think you are going to like it.
Due to the stateless nature of webforms, any controls that you add dynamically to a form on a postback will also need to be added back to the page and have it's server events rebound during the OnInit event.
I've created a minimal example that can demonstrate what's going on with this behavior so you can better understand what's happened.
ButtonTest.aspx
<%# Page Language="C#" AutoEventWireup="true" CodeBehind="ButtonTest.aspx.cs" Inherits="ButtonTest.ButtonTest" %>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title></title>
</head>
<body>
<form runat="server">
<asp:Panel runat="server" ID="ButtonPanel">
<asp:Button runat="server" ID="ButtonAdd" OnClick="ButtonAddClick" Text="Click Me"></asp:Button>
</asp:Panel>
</form>
</body>
</html>
And the code behind:
ButtonTest.aspx.cs
using System;
using System.Collections.Generic;
using System.Web.UI.WebControls;
namespace ButtonTest
{
public partial class ButtonTest : System.Web.UI.Page
{
static List<Button> buttons = new List<Button>();
static bool allowItToWork = true;
protected override void OnInit(EventArgs e)
{
if(Page.IsPostBack && allowItToWork)
{
foreach (var button in buttons)
{
button.Click += ButtonAddClick; // Comment me out and added button's will do nothing when clicked.
ButtonPanel.Controls.Add(button);
}
}
}
protected void ButtonAddClick(object sender, EventArgs e)
{
var button = new Button();
button.Click += ButtonAddClick;
button.Text = "Click Me Too";
buttons.Add(button);
ButtonPanel.Controls.Add(button);
}
}
}
You can toggle between desirable and undesirable behavior by changing the value of the allowItToWork boolean.
When it's set to true, the OnInit overload is adding all buttons back onto the page, as well as applying their event handlers again, because those handlers seem to be lost during the PostBack (unsure on why this happens.) You can click away and new buttons will be added onto the form forever and ever.
When it's set to false, the added button will appear whenever you click the initial button, but it won't fire an event handler as it's no longer bound, and clicking the original button repeatably won't continue to add additional buttons, you'll only ever see a single one, and that one will disappear on PostBack if clicked.
So, the end result of this is essentially that you're stuck reconstructing the whole shebang in the OnInit event.

C# - How to add and delete multiple controls dynamically on button click

I am trying to code a survey application which requires text boxes to be added and removed dynamically. I managed to create text boxes dynamically on button click but I'm trying to find out how to removed the text boxes dynamically. Currently the delete functions works well only if I remove text boxes starting from the last. When I try deleting any text boxes in the middle followed by a delete of the last text box, a blank text box is created instead. I'm new to programming and am unsure if this is the best method to use. Also, I would like to find out if it is possible to nest text boxes(allow users to add options to their multi choice questions) to created text boxes and retrieve values inside later.
Code behind:
public partial class Dynamic_Form : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
for (int i = 0; i < TotalNumberAdded; ++i)
{
AddQuestion(i + 1);
}
}
protected int TotalNumberAdded
{
get { return (int)(ViewState["TotalNumberAdded"] ?? 0); }
set { ViewState["TotalNumberAdded"] = value; }
}
protected void btn_add_Click(object sender, EventArgs e)
{
TotalNumberAdded++;
AddQuestion(TotalNumberAdded);
}
private void AddQuestion(int controlNumber)
{
Panel newquestion = new Panel();
newquestion.ID = "Panel_" + controlNumber;
TextBox questionbox = new TextBox();
questionbox.ID = "Question_" + controlNumber;
questionbox.Text = "Question";
Button BtnDelete = new Button();
BtnDelete.ID = "BtnDelete_" + controlNumber;
BtnDelete.Text = "Delete"+ controlNumber;
BtnDelete.Click += delete_Click;
DropDownList DDLType = new DropDownList();
DDLType.ID = "DDLType_" + controlNumber;
DDLType.Items.Insert(0, new ListItem("TextField", ""));
DDLType.Items.Insert(1, new ListItem("Multiple Choice", ""));
//add controls
questions.Controls.Add(newquestion);
newquestion.Controls.Add(questionbox);
newquestion.Controls.Add(DDLType);
newquestion.Controls.Add(BtnDelete);
}
private void delete_Click(object sender,EventArgs e)
{
Button btn = (Button)sender;
Control control = btn.Parent;
if (questions.Controls.Contains(control))
{
questions.Controls.Remove(control);
control.Dispose();
TotalNumberAdded--;
Response.Write("Number of Questions:" + TotalNumberAdded);
}
}
}
Html file:
<body>
<form id="form1" runat="server">
<div>
<h1>Test Form</h1>
<asp:Button ID="btn_add" runat="server" Text="Add" OnClick="btn_add_Click" />
</div>
<div id="questions" runat="server">
</div>
</form></body>
.
#Aaron Yong, You can do these scenarios from client side using jQuery or javascript too. I have given below code to achieve what you want from server side.
private void delete_Click(object sender,EventArgs e)
{
Button btn = (Button)sender;
Control control = btn.Parent;
if (questions.Controls.Contains(control))
{
TotalNumberAdded--;
questions.Controls.Clear();
for (int i = 0; i < TotalNumberAdded; ++i)
{
AddQuestion(i + 1);
}
Response.Write("Number of Questions:" + TotalNumberAdded);
}
}
You want to recreate controls again, i have added for loop and removed some code in delete click event, then you will achieve.
As i have given above answer, you can also remove below code from previous answered.
questions.Controls.Remove(control);
control.Dispose();
You will get exact answer

open textbox on calender day click

I have seen number of posts for this solution , But not getting satisfying answer
I am trying to Simply add textbox +button on Calender cell and open it on cell click ,
I can make a popup open on cells click .But not with Textbox of CellSize,
<asp:Calendar
ID="Calendar2"
runat="server"
NextPrevFormat="FullMonth"
SelectionMode="Day"
DayNameFormat="Full"
OnDayRender="Calendar1_DayRender"
VisibleDate="10/7/2008" OnSelectionChanged="Calendar2_SelectionChanged"
>
</asp:Calendar>
and calling DayRender event
protected void Calendar1_DayRender(object sender, DayRenderEventArgs e)
{
Label lbl = new Label();
lbl.Text = e.Day.DayNumberText.ToString();
lbl.Attributes.Add("onclick", "JavaScript:void(window.open('Test/Default.aspx'))");
lbl.Style.Add("cursor", "pointer");
e.Cell.Controls.Add(lbl);
}
How can I do it for a Textbox?
Inside you calendar event
protected void Calendar1_DayRender(object sender, DayRenderEventArgs e)
{
Button btn = new Button();
btn.Text = "+";
btn.Attributes.Add("onclick", "javascript:return btnClick(" + e.Day.DayNumberText + ")");
btn.Style.Add("cursor", "pointer");
TextBox txt = new TextBox();
txt.ID = e.Day.DayNumberText.ToString();
txt.Attributes.Add("style", "display:none;");
txt.Attributes.Add("onclick", "JavaScript:void(window.open('Test/Default.aspx'))");
e.Cell.Controls.Add(txt);
e.Cell.Controls.Add(btn);
}
Add the script tag in the aspx file
<script type="text/javascript">
function btnClick(id){
var txt = document.getElementById(id);
txt.attributes.removeNamedItem("style");
return false;
}
</script>
Since you've used javascript, i adhered to your compatibility. But i suggest you to used jquery.

EventHandler is not working for dynamic control

I have referred Error with the event handlers of dynamic linkbutton . It says to add event handlers in Page_Init or Page_Load. I tired following code. But the event handler is not fired when I click on the dynamic added link buttons. What need to be corrected here?
Note: The dynamic LinkButton controls are added in the click event of a button after some business validations (the business code is not given for brevity)
Markup
<form id="form1" runat="server">
<div>
<asp:LinkButton ID="lnkTest" runat="server" OnClick="LinkButton_Click">Static LinkButton</asp:LinkButton>
<br />
<asp:Button ID="btnAdd" runat="server" Text="Add" OnClick="btnAdd_Click" />
<br />
<asp:PlaceHolder ID="plhDynamicLinks" runat="server"></asp:PlaceHolder>
</div>
</form>
Code Behind
protected void Page_Load(object sender, EventArgs e)
{
foreach (Control ctrl in plhDynamicLinks.Controls)
{
LinkButton dynamicButton = (LinkButton)ctrl;
dynamicButton.Click += new EventHandler(LinkButton_Click);
}
if (Page.IsPostBack)
{
}
}
protected void Page_Init(object sender, EventArgs e)
{
int x = 0;
foreach (Control ctrl in plhDynamicLinks.Controls)
{
LinkButton dynamicButton = (LinkButton)ctrl;
dynamicButton.Click += new EventHandler(LinkButton_Click);
}
}
protected void LinkButton_Click(object sender, EventArgs e)
{
LinkButton clickedControl = (LinkButton)sender;
Response.Write(clickedControl.ID +" Link Button Clicked");
}
protected void btnAdd_Click(object sender, EventArgs e)
{
plhDynamicLinks.Controls.Clear();
LinkButton button1 = new LinkButton();
button1.ID = "D1";
button1.Text = "1";
plhDynamicLinks.Controls.Add(button1);
LinkButton button2 = new LinkButton();
button2.ID = "D2";
button2.Text = "2";
plhDynamicLinks.Controls.Add(button2);
}
It is mandatory to register all the required dynamic controls’ event handlers in the Page_Load/ Page_Init itself. One working example can be seen at Dynamic Control’s Event Handler’s Working
MarkUp
<form id="form1" runat="server">
<div>
<asp:Button ID="btnAdd" runat="server" Text="Add" OnClick="btnAdd_Click" />
<br />
<asp:PlaceHolder ID="plhDynamicLinks" runat="server"></asp:PlaceHolder>
</div>
</form>
CODE BEHIND
protected void Page_Load(object sender, EventArgs e)
{
if (Page.IsPostBack)
{
LinkButton lnk1 = new LinkButton();
lnk1.ID = "D1";
lnk1.Text = "A";
//Event handler must be registered in the Page_Load/Page_Init
lnk1.Click += new EventHandler(LinkButton_Click);
plhDynamicLinks.Controls.Add(lnk1);
LinkButton lnk2 = new LinkButton();
lnk2.ID = "D2";
lnk2.Text = "B";
lnk2.Click += new EventHandler(LinkButton_Click);
plhDynamicLinks.Controls.Add(lnk2);
LinkButton lnk3 = new LinkButton();
lnk3.ID = "D3";
lnk3.Text = "C";
lnk3.Click += new EventHandler(LinkButton_Click);
plhDynamicLinks.Controls.Add(lnk3);
LinkButton lnk4 = new LinkButton();
lnk4.ID = "D4";
lnk4.Text = "D";
lnk4.Click += new EventHandler(LinkButton_Click);
plhDynamicLinks.Controls.Add(lnk4);
}
}
protected void LinkButton_Click(object sender, EventArgs e)
{
PopulateLinksBasedOnCriteria();
LinkButton clickedControl = (LinkButton)sender;
Response.Write(DateTime.Now.ToString()+"___"+ clickedControl.ID + " Link Button Clicked" );
}
protected void btnAdd_Click(object sender, EventArgs e)
{
PopulateLinksBasedOnCriteria();
}
private void PopulateLinksBasedOnCriteria()
{
plhDynamicLinks.Controls.Clear();
if (DateTime.Now.Second < 30)
{
LinkButton linkButton1 = new LinkButton();
linkButton1.ID = "D1";
linkButton1.Text = "1";
plhDynamicLinks.Controls.Add(linkButton1);
LinkButton linkButton2 = new LinkButton();
linkButton2.ID = "D2";
linkButton2.Text = "2";
plhDynamicLinks.Controls.Add(linkButton2);
}
else
{
LinkButton linkButton3 = new LinkButton();
linkButton3.ID = "D3";
linkButton3.Text = "3";
plhDynamicLinks.Controls.Add(linkButton3);
LinkButton linkButton4 = new LinkButton();
linkButton4.ID = "D4";
linkButton4.Text = "4";
plhDynamicLinks.Controls.Add(linkButton4);
}
}
Dynamic controls must be re-created on every postback, this Article is a good link about how to persist dynamic controls and their state.
Add javascript onClick attribute to the dymanic control and set hidden field values which is required for the control event. Onclick of the dymanic grid, the will postback and will get the hidden field value. In page load call a method to do the job if the hidden field has value and make it null after doing the job.

Dynamic Control’s Event Handler’s Working

I have following code that adds dynamic LinkButton on the click event of a normal button. The LinkButtons need a EventHandler “LinkButton_Click“. Since the event handler need to be registered while Page_Load/Page_Init itself, I am first adding all the possible links within Page_Load (in postback scenario). (There are totally fours linkbuttons; only two will be displayed in the screen based on business scenario)
The code is working fine and the event handlers are getting invoked on click event.
Note: The business scenario is – if the current time’s second portion is less than 30, the first two LinkButtons need to be displayed; if greater than 30 the last two LinkButtons need to be displayed.
Note: The controls are cleared and added again inside PopulateLinksBasedOnCriteria() method
QUESTIONS
In the PopulateLinksBasedOnCriteria() method, I am newly creating the link button instances. Still the event handler is firing. This is working because the ID that got added in the Page_Load is same. Is there any MSDN reference that substantiate this behavior? (I.e. the event handler will be based on the IDs registered while Page_Load/Page_Init. This will work even if the controls are cleared and added again)
There is duplicate code in creating LinkButtons – one inside Page_Load and other inside PopulateLinksBasedOnCriteria() method. Is there a better way to achieve this business task without duplicate code?
MarkUp
<form id="form1" runat="server">
<div>
<asp:Button ID="btnAdd" runat="server" Text="Add" OnClick="btnAdd_Click" />
<br />
<asp:PlaceHolder ID="plhDynamicLinks" runat="server"></asp:PlaceHolder>
</div>
</form>
CODE BEHIND
protected void Page_Load(object sender, EventArgs e)
{
if (Page.IsPostBack)
{
LinkButton lnk1 = new LinkButton();
lnk1.ID = "D1";
lnk1.Text = "A";
//Event handler must be registered in the Page_Load/Page_Init
lnk1.Click += new EventHandler(LinkButton_Click);
plhDynamicLinks.Controls.Add(lnk1);
LinkButton lnk2 = new LinkButton();
lnk2.ID = "D2";
lnk2.Text = "B";
lnk2.Click += new EventHandler(LinkButton_Click);
plhDynamicLinks.Controls.Add(lnk2);
LinkButton lnk3 = new LinkButton();
lnk3.ID = "D3";
lnk3.Text = "C";
lnk3.Click += new EventHandler(LinkButton_Click);
plhDynamicLinks.Controls.Add(lnk3);
LinkButton lnk4 = new LinkButton();
lnk4.ID = "D4";
lnk4.Text = "D";
lnk4.Click += new EventHandler(LinkButton_Click);
plhDynamicLinks.Controls.Add(lnk4);
}
}
protected void LinkButton_Click(object sender, EventArgs e)
{
PopulateLinksBasedOnCriteria();
LinkButton clickedControl = (LinkButton)sender;
Response.Write(DateTime.Now.ToString()+"___"+ clickedControl.ID + " Link Button Clicked" );
}
protected void btnAdd_Click(object sender, EventArgs e)
{
PopulateLinksBasedOnCriteria();
}
private void PopulateLinksBasedOnCriteria()
{
plhDynamicLinks.Controls.Clear();
if (DateTime.Now.Second < 30)
{
LinkButton linkButton1 = new LinkButton();
linkButton1.ID = "D1";
linkButton1.Text = "1";
plhDynamicLinks.Controls.Add(linkButton1);
LinkButton linkButton2 = new LinkButton();
linkButton2.ID = "D2";
linkButton2.Text = "2";
plhDynamicLinks.Controls.Add(linkButton2);
}
else
{
LinkButton linkButton3 = new LinkButton();
linkButton3.ID = "D3";
linkButton3.Text = "3";
plhDynamicLinks.Controls.Add(linkButton3);
LinkButton linkButton4 = new LinkButton();
linkButton4.ID = "D4";
linkButton4.Text = "4";
plhDynamicLinks.Controls.Add(linkButton4);
}
}
I would suggest detecting what causes the PostBack in Page_Load Event On postback, how can I check which control cause postback in Page_Init event and then
if (Page.IsPostBack && *PostBackControl.Name=="btnAdd"*)
{
if (DateTime.Now.Second < 30)
{
LinkButton lnk1 = new LinkButton();
lnk1.ID = "D1";
lnk1.Text = "A";
//Event handler must be registered in the Page_Load/Page_Init
lnk1.Click += new EventHandler(LinkButton_Click);
plhDynamicLinks.Controls.Add(lnk1);
LinkButton lnk2 = new LinkButton();
lnk2.ID = "D2";
lnk2.Text = "B";
lnk2.Click += new EventHandler(LinkButton_Click);
plhDynamicLinks.Controls.Add(lnk2);
} else
{
LinkButton lnk3 = new LinkButton();
lnk3.ID = "D3";
lnk3.Text = "C";
lnk3.Click += new EventHandler(LinkButton_Click);
plhDynamicLinks.Controls.Add(lnk3);
LinkButton lnk4 = new LinkButton();
lnk4.ID = "D4";
lnk4.Text = "D";
lnk4.Click += new EventHandler(LinkButton_Click);
plhDynamicLinks.Controls.Add(lnk4);
}
}
}

Categories

Resources