How to make dynamically added buttons clickable - c#

I am creating a C# application which fetches data from a database, and dynamically creates 5 textBoxes and one button in a single row.
The number of rows present in the database equals the number of rows of textBoxes and buttons that are created.
I could successfully create the rows of textBoxes and buttons, the textBoxes are even capable of displaying data that is being fetched from the database.
My trouble however is that the button that is generated, does nothing when clicked, now that is not unexpected since i haven't created a handler to handle the click event. But i am confused on how to dynamically create the click even handler for the buttons that are again generated dynamically.
Below is the code sample that generated the textBoxes and buttons.
for (int i = 3; i <= count; i++)
{
com.Parameters[0].Value = i;
using (SqlCeDataReader rd = com.ExecuteReader())
if (rd.Read())
{
pname = (rd["pname"].ToString());
cname = (rd["cname"].ToString());
budget = (rd["budget"].ToString());
advance = (rd["advance"].ToString());
ddate = (rd["ddate"].ToString());
TextBox tobj = new TextBox();
tobj.Location = new Point(10, (40 + ((i - 2) * 20)));
tobj.Tag = 1;
tobj.Text = pname;
tobj.AutoSize = false;
tobj.Width = 150;
tobj.ReadOnly = true;
this.Controls.Add(tobj);
TextBox tobj1 = new TextBox();
tobj1.Location = new Point(160, (40 + ((i - 2) * 20)));
tobj1.Tag = 2;
tobj1.Text = cname;
tobj1.AutoSize = false;
tobj1.Width = 150;
tobj1.ReadOnly = true;
this.Controls.Add(tobj1);
TextBox tobj2 = new TextBox();
tobj2.Location = new Point(310, (40 + ((i - 2) * 20)));
tobj2.Tag = 3;
tobj2.Text = budget;
tobj2.AutoSize = false;
tobj2.Width = 100;
tobj2.ReadOnly = true;
this.Controls.Add(tobj2);
TextBox tobj3 = new TextBox();
tobj3.Location = new Point(410, (40 + ((i - 2) * 20)));
tobj3.Tag = 4;
tobj3.Text = advance;
tobj3.AutoSize = false;
tobj3.Width = 100;
tobj3.ReadOnly = true;
this.Controls.Add(tobj3);
TextBox tobj4 = new TextBox();
tobj4.Location = new Point(510, (40 + ((i - 2) * 20)));
tobj4.Tag = 5;
tobj4.Text = ddate;
tobj4.AutoSize = false;
tobj4.Width = 100;
tobj4.ReadOnly = true;
int due = 0;
due = int.Parse(ddate);
if (due < 5)
{
tobj4.BackColor = System.Drawing.Color.Red;
}
this.Controls.Add(tobj4);
Button button = new Button();
button.Left = 620;
button.Tag = i;
button.Height = 20;
button.Text = "Details";
button.Top = (40 + ((i - 2) * 20));
this.Controls.Add(button);
}
}
Please give me some ideas on how to generate the click event handler.

Answer part:
Add this:
button.Tag = i;
button.Click += handleTheClick;
...
private void handleTheClick(object sender, EventArgs e){
Button btn = sender as Button;
int row = (int)btn.Tag;
}
Un-answer:
You should reconsider your design. Including coordinates in your data processing code is a really bad idea in 2013, try using ListView, ListBox, GridView or better - switch to WPF.

You need to subscribe to the Click events:
button.Click += ... some event handler ...
You can use a method for the handler:
button.Click += MyEventHandlerMethod;
// put this method somewhere in your Form class
void MyEventHandlerMethod( object sender, EventArgs args )
{
...
Or even a lambda:
button.Click += ( s, e ) => HandleClick( ... any parameters here ... );
// put this method somewhere in your Form class
void HandleClick( ... required parameters ... )
{
...
As a hint, you can look in the .designer.cs file of a normal Form to see how things are done.

Related

How to apply a Focus() function on Dynamically Created TextBox in windows forms?

When dynamically creating textBoxes how can we make one of the textBoxes have the Focus() function on it?
namespace Dinamik_Arac
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
for (int i = 1; i <= 5; i++)
{
TextBox txt = new TextBox();
Point txtKonum = new Point(300, i * 30);
txt.Location = txtKonum;
txt.Name = "TextBox" + i;
txt.Text = i.ToString();
this.Controls.Add(txt);
}
}
}
}
Simply writing TextBox4.Focus() into the for loop is not working.
for (int i = 1; i <= 5; i++)
{
TextBox txt = new TextBox();
Point txtKonum = new Point(300, i * 30);
txt.Location = txtKonum;
txt.Name = "TextBox" + i;
txt.Text = i.ToString();
if(i == 4)
{
txt.Focus();
}
this.Controls.Add(txt);
}
This code does not work either.
enter image description here
As you can see in the picture there is no cursor on the 4th textBox.
Solved,
just put the this.Controls.Add(txt); code before the if statement,
{
TextBox txt = new TextBox();
Point txtKonum = new Point(300, i * 30);
txt.Location = txtKonum;
txt.Name = "TextBox" + i;
txt.Text = i.ToString();
this.Controls.Add(txt);
if(i == 4)
{
txt.Focus();
}
}
I've been playing around with this problem looking for an alternative and more versatile approach, and I came up with this method for giving focus to your your 4th iteration of dynamically created textboxes:
string focusedTextBox = "TextBoxName";//in this case "Textbox4"
Control focusControl = this.Controls[focusedTextBox];
focusControl.Focus();
In your application, it would look like this:
private void button1_Click(object sender, EventArgs e)
{
for (int i = 1; i <= 5; i++)
{
TextBox txt = new TextBox();
Point txtKonum = new Point(300, i * 30);
txt.Location = txtKonum;
txt.Name = "TextBox" + i;
txt.Text = i.ToString();
this.Controls.Add(txt);
}
Control focusControl = this.Controls["Textbox4"];
focusControl.Focus();
}
The obvious major advantage to this approach is that it will work from other places in the program. The only thing that has to be taken into account when calling this from a seperate method is that if the control.name doesn't exist an exception will be thrown, so it would probably be a good idea to set up some sort of safeguard or exception handling for that usage.

Get the number of a certain Button in stack panel

Hey I would like to create a stack panel with multiple buttons in it and when I press one, it tells me which button it is. Like when I press the second button from the top, I get the number 2 back and so on.
The buttons are created with this loop:
for (int i = 0; i < LBresponse.Items.Count; i++)
{
System.Windows.Controls.Button BTclear = new Button();
BTclear.Content = "Clear";
BTclear.Width = 50;
BTclear.Height = 20;
BTclear.HorizontalAlignment = HorizontalAlignment.Right;
BTclear.Click += Button_Click;
BTclear.IsEnabled = true;
STPresponse.Children.Add(BTclear);
}
I could do it with the location of the button but I hope there is a better solution.
One Idea would be to put the number into the context when the button is created but this would not be pretty.
You could store the number or index somewhere, for example in the Tag property:
for (int i = 0; i<LBresponse.Items.Count; i++)
{
System.Windows.Controls.Button BTclear = new Button();
BTclear.Tag = i;
BTclear.Content = "Clear";
BTclear.Width = 50;
BTclear.Height = 20;
BTclear.HorizontalAlignment = HorizontalAlignment.Right;
BTclear.Click += (ss, ee) =>
{
MessageBox.Show(((Button)ss).Tag.ToString());
};
BTclear.IsEnabled = true;
STPresponse.Children.Add(BTclear);
}

How to get the index of dynamically created multiple panels in C# GUI form,when a checkbox is clicked in one of the dynamically created panel

I have a split container panel in GUI Form.When a button is clicked in left panel,it pulls out information along with multiple checkboxes on dynamically created panels on the right panel using a loop.Each panel on the right side can have multiple checkboxes based on some condition.For example, the first panel has one checkbox and the second panel below the first has got 8 checkboxes in the same row.When one of the checkboxes in second panel is clicked, I have to get the index of the that panel to do some manipulation. Tab index does not help me to get one as each panel can have any number of checkboxes.I spent a day to get around the problem with no luck. Your help will be much appreciated. I have posted the code below.
for (int j = 0; j < numOfSensors.Count; j++)
{
sensorpanel = new Panel();
sensorpanel.Size = new Size(800, 60);
sensorpanel.Location = new Point(0, Y);
sensorpanel.BackColor = Color.LightGray;
sensorpanel.Paint += new PaintEventHandler(panel_Paint);
Button sensor = new Button();
sensor.Size = new Size(200, 50);
sensor.Location = new Point(1, 1);
sensor.FlatStyle = FlatStyle.Flat;
sensor.FlatAppearance.BorderColor = Color.LightGray;
String sensorType = "Occupancy";
sensor.TextAlign = ContentAlignment.MiddleLeft;
sensor.BackColor = Color.LightGray;
sensor.ForeColor = Color.Black;
sensorpanel.Controls.Add(sensor);
if (sensorType.Equals("Occupancy"))
{
CheckBox cb = new CheckBox();
cb.Location = new Point(380, 15);
cb.Size = new Size(20, 17);
cb.Checked = checkBox(j,0);
cb.Text = "Occupancy";
checksensorbuttons.Add(cb);
cb.CheckedChanged += new EventHandler(cb_CheckChanged);
sensorpanel.Controls.Add(cb);
}
else if (sensorType.Equals("Multi-input:Digital"))
{
int xLoc = 210;
int yLoc = 15;
for (int k = 16; k <32; k+=2)
{
CheckBox cb = new CheckBox();
cb.Location = new Point(xLoc, yLoc);
cb.Size = new Size(20, 17);
cb.Checked = checkBox(j,k);
cb.Text = "Multi-input";
cb.CheckedChanged += new EventHandler(cb_CheckChanged);
sensorpanel.Controls.Add(cb);
xLoc += 30;
}
splitContainer.panel2.Controls.Add(sensorpanel);
}
//checkedchanged eventhandler
private void cb_CheckChanged(object sender, EventArgs e)
{
CheckBox checkbox = (CheckBox)sender;
if (checkbox.Text.Equals("Occupancy"))
{
// How to get the index of the panel when a checkbox in corresponding panel is checked?
if (checkbox.Checked == true)
{
//some manipulation
}
else
{
//some manipulation
}
}
else if (checkbox.Text.Equals("Multi-input"))
{
//get index of the panel where one of the checkboxes are clicked
if (checkbox.Checked == true)
{
//do some manipulation
}
else
{
//do some manipulation
}
}
There are multiple ways
Use Name property of the checkbox. When the checkbox is created assign it a logical name which makes it easier to identify it. Only string can be used here.
Use Tag property of the checkbox to preserve the data you want to refer it. Its good place to store any object and not just string.
Use Parent property of the checkbox to access checkbox's parent properties.
As a best practice, assign a logical name to the dynamic controls. This is the best way to identify the control.
sensorpanel.Name = "panel" + j.ToString();
this.Controls.Add(sensorpanel);
:
:
cb.Text = "Occupancy";
cb.Tag = "panel Index = " + j.ToString();
cb.Name = "panel" + j.ToString() + "_" + "cb_" + cb.Text;
sensorpanel.Controls.Add(cb);
void cb_CheckedChanged(object sender, EventArgs e)
{
CheckBox checkbox = (CheckBox)sender;
string mssg;
mssg = "Name = " + checkbox.Name;
mssg = "tag = " + checkbox.Tag;
mssg = "Parent text = " + checkbox.Parent.Text;
mssg = "Parent name = " + checkbox.Parent.Name;
MessageBox.Show(mssg);
}

How do I add this panels to tabcontrol instead of adding them to the form?

Here is the code. Help will be much obliged. I want the panels to be added to tabePage1, but it is being added to the form instead.
private void tabPage1_Click(object sender, EventArgs e)
{
int i, j;
for (i = 1; i <= 3; i++)
{
for (j = 1; j <= 4; j++)
{
Panel a = new Panel();
a.Location = new Point(i * 200, j * 50);
a.Width = 180;
a.Height = 40;
a.Name = "Rom " + (((i * 4) - 3) + (j - 1));
a.BackColor = Color.Yellow;
a.AllowDrop = true;
a.DragDrop += new System.Windows.Forms.DragEventHandler(this.panel1_DragDrop);
a.DragOver += new System.Windows.Forms.DragEventHandler(this.panel1_DragOver);
a.Visible = true;
Label l = new Label();
l.Location = new Point(10, 10);
l.Width = 180;
l.Text = a.Name;
a.Controls.Add(l);
l.AllowDrop = true;
this.Controls.Add(a);
This code:
this.Controls.Add(a);
adds the control to the Form, because your tabPage1_Click method is in a subclass of Form (making this refer to the Form). To add the panels to tabPage1, do this instead:
tabPage1.Controls.Add(a);
Incidentally, do you really want to add all the panels to a single TabPage, or do you want to create a TabPage for each panel? If the latter, the code will obviously look different.
Edit: in answer to your comment, you can add to a different TabPage by referring to it by name as above (e.g. tabPage2.Controls.Add(a);) or, if you want to add a set of panels to each TabPage in your TabControl, you could do something like this:
foreach (TabPage tp in yourTabControl.TabPages)
{
// create panel...
tp.Controls.Add(a);
// ...
}

why doesnt my panel show all my buttons in my c# application?

my panel in my windows form application doesn't include all the buttons i asked it to. It shows only 1 button, Here is the code
private void AddAlphaButtons()
{
char alphaStart = Char.Parse("A");
char alphaEnd = Char.Parse("Z");
for (char i = alphaStart; i <= alphaEnd; i++)
{
string anchorLetter = i.ToString();
Button Buttonx = new Button();
Buttonx.Name = "button " + anchorLetter;
Buttonx.Text = anchorLetter;
Buttonx.BackColor = Color.DarkSlateBlue;
Buttonx.ForeColor = Color.GreenYellow;
Buttonx.Width = 30;
Buttonx.Height = 30;
this.panelButtons.Controls.Add(Buttonx);
//Buttonx.Click += new System.EventHandler(this.MyButton_Click);
}
}
Aren't they all going to be on the same position?
Try setting Buttonx.Location = new Point(100, 200);
(but with different points for different buttons)
You could use a FlowLayoutPanel, which would take care of the layout for you, or you need to track the locations yourself, or which could look something like this:
private void AddAlphaButtons()
{
char alphaStart = Char.Parse("A");
char alphaEnd = Char.Parse("Z");
int x = 0; // used for location info
int y = 0; // used for location info
for (char i = alphaStart; i <= alphaEnd; i++)
{
string anchorLetter = i.ToString();
Button Buttonx = new Button();
Buttonx.Name = "button " + anchorLetter;
Buttonx.Text = anchorLetter;
Buttonx.BackColor = Color.DarkSlateBlue;
Buttonx.ForeColor = Color.GreenYellow;
Buttonx.Width = 30;
Buttonx.Height = 30;
// set button location
Buttonx.Location = new Point(x, y);
x+=30;
if(x > panel1.Width - 30)
{
x = 30;
y+=30;
}
this.panelButtons.Controls.Add(Buttonx);
//Buttonx.Click += new System.EventHandler(this.MyButton_Click);
}
}

Categories

Resources