Creating unique event handlers for dynamically created buttons - c#

I want to add buttons to my page dynamically. It will depend on the number of results from a SELECT statement. I
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
for (int i = 0; i < Query.length; i++)
{
Button btn = new Button();
btn.ID = "Button" + i;
btn.Click += new EventHandler(btn_Click());
btn.Text = i.ToString();
pagingPanel.Controls.Add(btn);
}
}
}
But I want each button to have it's own custom event handler. If I click one button, I want it do have a different result than if I click another. I would like to do something like this where I can pass an aditional parameter:
protected void btn_Click(object sender, EventArgs e, string test)
{
System.Diagnostics.Debug.WriteLine(test);
}
Perhaps I don't know which objects to pass? Or maybe I am approaching this the wrong way.
How do I achieve the desired results?

Try this:
protected void Page_Load(object sender, EventArgs e)
{
// you do not use !IsPostBack here
//count of func must be equal with 'Query.Length'
string[,] arr ={
{"func1","hello world"},
{"func2","Hello ASP.NET"}
};
for (int i = 0; i < Query.Length; i++)//I assume length is 2
{
Button btn = new Button();
btn.ID = arr[i, 0];
btn.CommandArgument = arr[i, 1];
btn.Click += new EventHandler(btn_Click);
btn.Text = i.ToString();
pagingPanel.Controls.Add(btn);
}
}
protected void btn_Click(object sender, EventArgs e)
{
Button btn = (Button)sender;
System.Reflection.MethodInfo methodInfo = typeof(_Default2).GetMethod(btn.ID); //_Default2 is class name of code behind
if (methodInfo != null)
{
object[] parameters = new object[] { btn.CommandArgument};
methodInfo.Invoke(this,parameters);
}
}
public void func1(object args)
{
string test = args.ToString();
Response.Write(test);
}
public void func2(object args)
{
string test = args.ToString();
Response.Write(test);
}

First and foremost - you have to create buttons whether it is postback or not. The button click is the reason for the postback, if you don't have buttons - what will be clicking?
Second, add to your page class:
Dictionary<Button, ButtonInfo> fButtonLookup = new Dictionary<Button, ButtonInfo>();
Then, where you create buttons:
fButtonLookup.Clear();
for (int i = 0; i < Query.length; i++)
{
Button btn = new Button();
fButtonLookup.Add(btn, new ButtonInfo() { whatever information about this button you want to keep});
...
}
Then, in your button click:
protected void btn_Click(object sender, EventArgs e)
{
Button btn = (Button)sender;
if (fButtonLookup.ContainsKey(btn))
{
ButtonInfo info = fButtonLookup[btn];
// do waht you need with button information
}
}

You could just check sender to see which button was clicked:
protected void btn_Click(object sender, EventArgs e)
{
if (sender == btnOne)
performBtnOne("foo");
else if (sender == btnTwo)
performButtonTwo("bar");
}

To expand on itsme86...
protected void btn_Click(object sender, EventArgs e)
{
Button btn = (Button)sender; //Now you have an instantiated version of the button pressed.
switch (btn.Name)
{
case "foo":
performBtnOne();
break;
case "bar":
performBtnTwo();
break;
default:
performUnexpectedButton();
break;
}
}

Related

How to get an attribute from an unspecified object?

My program dynamically creates a number of buttons at runtime. All of them get attached to an EventHandler, which links to the same method. How to know which button was pressed when the method executes? I tried using sender.Name, because object sender is a Button at runtime, but it doesn't compile.
List<Button> buttons = new List<Button>();
private void Form1_Load(object sender, EventArgs e)
{
for (int i = 1; i < 3; i++)
{
buttons.Add(new Button() { Name = "btn" + i });
buttons.Last().Click += new EventHandler(btn_Click);
}
}
public void btn_Click(object sender, EventArgs e)
{
MessageBox.Show(sender.Name + " is clicked");
}
You are on the right track.
The problem you have is that in btn_Click the sender is a generic object, so the compiler doesn't know what type it is, so you need to tell it by casting.
public void btn_Click(object sender, EventArgs e)
{
Button senderButton = (Button)sender;
MessageBox.Show(senderButton.Name + " is clicked");
}

Accessing and checking values of dynamic controls ASP.NET

I have a scenario. following is the code:
Home.aspx.cs
protected void Button1_Click(object sender, EventArgs e)
{
try
{
if (!String.IsNullOrEmpty(txtbox_query.Text.Trim()))
{
if (isTrue)
{
// To do statements
}
else
{
List<RequestAndResponse.Parameter> parameters = request.getParameter(txtbox_query.Text.Trim(), sourcePath, parameterValue);
Session["Data"] = parameters;
Response.Redirect("Result.aspx",false);
}
}
}
catch (Exception error)
{
Response.Write(error.Message);
}
}
Result.aspx.cs
protected void Page_Load(object sender, EventArgs e)
{
parameters = (List<RequestAndResponse.Parameter>)Session["Data"];
ContentPlaceHolder content = (ContentPlaceHolder)this.Form.FindControl("MainContent");
for (int j = 1; j <= _arrViewState; j++)
{
string _id = j.ToString();
TextBox txtfname = new TextBox();
txtfname.ID = "TextBox_" + _id + "_";
txtfname.Width = 160;
txtfname.Text = parameters[(j - 1)].Value.ToUpper();
txtfname.Attributes.Add("style", "color:#015D84;font-weight:bold;font-size:12px;padding:10px;");
txtfname.EnableViewState = true;
content.Controls.Add(txtfname);
content.Controls.Add(new LiteralControl("<br/>"));
}
Button btnSubmit = new Button();
btnSubmit.ID = "btnSubmit";
btnSubmit.Text = "Submit";
btnSubmit.Click += new System.EventHandler(btnSubmit_click);
btnSubmit.Enabled = false;
content.Controls.Add(btnSubmit);
}
protected void btnSubmit_click(object sender, EventArgs e)
{
// How to find the dynamically created textbox
}
Now How to find the dynamically created controls
I know the basic like:
Form.FindControl("TextBox ID");
But here i dont know the textbox id and also i even dont know how many textbox will be their as it totally depends on user input i.e. from 2 TO N textboxes
What i want is on bttn_Click i will fetch the text from all the textboxes
How will i achieve this.
Also i want to check if all Textbox is empty or not on bttn_Click
Enumerate controls as follows
protected void btnSubmit_click(object sender, EventArgs e)
{
ContentPlaceHolder content = (ContentPlaceHolder)this.Form.FindControl("MainContent");
foreach (Control c in content.Controls)
{
if (c is TextBox)
{
TextBox txt = (TextBox)c;
// do something, e.g. Response.Write(txt.Text);
}
}
}

Click events on Array of buttons

How can I get the name of the object last clicked on a panel? The trick is there is a big array of buttons on the panel (btn[1] ... btn [200]). How can I check if I clicked on button b[180], or b[11] or even outside the panel (no button)? Also the buttons are generated at page load via coding.
Thank you. Anna
EDIT:
Thank you! Another issue that arose (this generated a NULL object reference):
I have a method on the same level as buttonHandler(), it is named HowManyClicked() and it's called from within buttonHandler(). Inside HowManyClicked() I want to identify Button btn1 = Panel2.FindControl(x) as Button; where x is, for example, buttonArray[2,3]. But I always get NULL. Is the button array buttonArray not identifiable by name once out of the method that generated it??
public void buttonHandler(object sender, EventArgs e)
{
Button btn = sender as Button;
//string tt = btn.ToolTip.ToString();
btn.BackColor = Color.Red;
statusL.Text = HowManyClicked().ToString();
}
public int HowManyClicked()
{
int sum=0;
for (int a = 0; a < 10; a++)
for (int b = 0; b < 14; b++)
{
string x = "buttonArray[" + a + ", " + b + "]";
statusL.Text = x;
Button btn1 = Panel2.FindControl(x) as Button;
if (btn1.BackColor == Color.Red) sum += 1;
}
return sum;
}
As #AVD commented you can get the button originating the postback casting the sender object, you can also use the CommandName and CommandArgument properties from the button object (they are usually used when the button is inside a Grid, DataList etc but you can use them in this context if you need):
protected void Page_Init(object sender, EventArgs e)
{
var s = Enumerable.Range(1, 10);
foreach (var item in s)
{
var b = new Button();
b.Text = "My Button " + item.ToString();
b.CommandName = "custom command";
b.CommandArgument = item.ToString();
b.Click += new EventHandler(b_Click);
this.myPanel.Controls.Add(b);
}
}
void b_Click(object sender, EventArgs e)
{
var current = sender as Button;
this.lblMessage2.Text = "Clicked from array buttons: <br/>Command Name: " + current.CommandName + "<br/>Args: " + current.CommandArgument + "<br/>Button Unique ID: " + current.UniqueID + "<br/>Client ID: " + current.ClientID;
}
Page:
<asp:Panel runat="server" ID="myPanel">
</asp:Panel>
<asp:Label ID="lblMessage2" runat="server" />
This code generates something like:
As an additional note, Microsoft recommends to create dynamic controls in the PreInit event or in case you are using a master page, in the Init event
source
Edited
protected void Page_Load(object sender, EventArgs e)
{
if (!this.IsPostBack)
{
this.ViewState["count"] = 0;
}
}
protected void Page_Init(object sender, EventArgs e)
{
var s = Enumerable.Range(1, 10);
foreach (var item in s)
{
var b = new Button();
b.Text = "My Button " + item.ToString();
b.Click += new EventHandler(buttonHandler);
this.myPanel.Controls.Add(b);
}
}
void buttonHandler(object sender, EventArgs e)
{
// update here your control
var b = sender as Button;
b.BackColor = Color.Red;
HowManyClicked();
}
private void HowManyClicked()
{
var c = (int)this.ViewState["count"];
c++;
this.ViewState["count"] = c;
this.lblMessage2.Text = "Clicked controls: " + this.ViewState["count"].ToString();
}
This produced:
How can I get the name of the object last clicked on a panel?
The first parameter of click handler returns the reference of control/object has raised the event.
public void buttonHandler(object sender, EventArgs e)
{
Button btn=sender as Button;
....
}
I just figured out another fix by just redefining HowManyClicked() so I am adding it here below. Not sure still why the first method (the one in my question) didn't work also. Here goes:
public int HowManyClicked()
{
int sum=0;
foreach (Control cnt in this.Panel2.Controls)
if (cnt is Button)
{
Button btn = (Button)cnt;
if (btn.BackColor == Color.Red)
sum += 1;
}
return sum;
}
}
Thanks everyone!

Problem with programmatically generated controls

public partial class Default2 : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
GenerateButtons generate = new GenerateButtons();
generate.Generate5Controls(PlaceHolder1);
}
}
class GenerateButtons
{
PlaceHolder placeHolder;
public void Generate5Controls(PlaceHolder placeH)
{
placeHolder = placeH;
for (int i = 0; i < 5; i++)
{
Button newBtn = new Button();
newBtn.Click += btn_Click;
newBtn.Text = "PageLoadButton Created. Number: "+i;
placeHolder.Controls.Add(newBtn);
}
}
public void btn_Click(object sender, EventArgs e)
{
Button newBTN = new Button();
newBTN.Text = "A New Button was added by the button event btn_click";
newBTN.Click += btn2_Click;
placeHolder.Controls.Add(newBTN);
}
public void btn2_Click(object sender, EventArgs e)
{
Button newBTN = new Button();
newBTN.Text = "A New Button was added by the button event btn2_click";
placeHolder.Controls.Add(newBTN);
}
}
I want the events btn_click & btn2_click to fire every post back.. When i click the button that was programmatically created it disappears after each postback and its event doesnt fire (btn2_click). I know i could generate the button at the postback.. But I dont want to do that!! I want to know how I could update the state of the placeholder... so that the only button will appear and the 5 buttons generated in Generate5Controls(PlaceHolder placeH) to disappear.
I could use a bool Viewstate to prevent this generate.Generate5Controls(PlaceHolder1); from being execute..
But the question is how do I make the programmatically generated button to appear!?
You should generate controls on every PostBack or you can generate controls once, save in session and add generated controls from session on page_load event.
protected void Page_Load(object sender, EventArgs e)
{
if(Session["GeneratedButtons"] == null)
{
GenerateButtons generate = new GenerateButtons();
generate.Generate5Controls(PlaceHolder1);
}
else
{
List<Control> generatedControls = Session["GeneratedButtons"] as List<Control>;
foreach(Control oneControl in generatedControls)
{
PlaceHolder1.Controls.Add(oneControl);
}
}
}
class GenerateButtons
{
PlaceHolder placeHolder;
public void Generate5Controls(PlaceHolder placeH)
{
placeHolder = placeH;
List<Control> generatedControls = new List<Control>();
for (int i = 0; i < 5; i++)
{
Button newBtn = new Button();
newBtn.Click += btn_Click;
newBtn.Text = "PageLoadButton Created. Number: "+i;
placeHolder.Controls.Add(newBtn);
AddControlToSession(newBtn);
}
}
public void btn_Click(object sender, EventArgs e)
{
Button newBTN = new Button();
newBTN.Text = "A New Button was added by the button event btn_click";
newBTN.Click += btn2_Click;
placeHolder.Controls.Add(newBTN);
AddControlToSession(newBtn);
}
public void btn2_Click(object sender, EventArgs e)
{
Button newBTN = new Button();
newBTN.Text = "A New Button was added by the button event btn2_click";
placeHolder.Controls.Add(newBTN);
AddControlToSession(newBtn);
}
private void AddControlToSession(Control ctrl)
{
List<Control> generatedControls = Session["GeneratedButtons"] as List<Control>;
if(generatedControls == null)
{
generatedControls = new List<Control>();
}
generatedControls.Add(ctrl);
Session["GeneratedButtons"] = generatedControls;
}
}

dynamically created controls disappears when click

the dynamic controls went missing right after i click it, why is this happening, and how do i fix it.
protected void Page_Load(object sender, EventArgs e)
{
/*DropDownList1_SelectedIndexChanged(sender, e);
Label1.Text += "<br/>huh?";
Label1.Text = MapPath("dawd");*/
}
protected void DropDownList1_SelectedIndexChanged(object sender, EventArgs e)
{
//PlaceHolder1.Controls.Clear();
for (int i = 0; i < DropDownList1.SelectedIndex + 1; i++)
{
CheckBox cb = new CheckBox();
cb.AutoPostBack = true;
cb.CheckedChanged += new EventHandler(cb_CheckedChanged);
PlaceHolder1.Controls.Add(cb);
PlaceHolder1.Controls.Add(new LiteralControl("<br/>"));
}
}
void cb_CheckedChanged(object sender, EventArgs e)
{
//DropDownList1_SelectedIndexChanged(sender, e);
Label1.Text += "<br/>adsd";
//throw new NotImplementedException();
}
cheers, Jaf
Dynamically created controls have to be recreated in every postback, or they will not be available and non of their events will fire.
You are only ever adding the checkboxes when the dropdownlist changes, so any other postback will not add them.
It is best to create your dynamic controls on the page OnInit event.
Read about the page life cycle here.
Create a panel
Do not create on page_load
Add this code
protected override void CreateChildControls()
{
base.CreateChildControls();
loadCheckbox();
}
public void loadCheckbox()
{
int checkCount = 10;
CheckBox[] chk = new CheckBox[checkCount];
for(int i == 0; i<=10; i++)
{
chk[i] = new CheckBox();
chk[i].ID = rCmt.cmtkey;
chk[i].Text = rCmt.rootcommitteename;
Panel1.Controls.Add(chk[i]);
}
}

Categories