How to dynamically create buttons and add events to them? - c#

I have array of buttons, and array of labels:
Label[] labels = new Label[10];
Button[] but = new Button[10];
While clicking the other button I want to dynamically create new button and new label from the array, i also want the but[i] to change the tex of labels[i]:
private void button1_Click(object sender, EventArgs e)
{
labels[i] = new Label();
labels[i].Location = new System.Drawing.Point(0, 15+a);
labels[i].Parent = panel1;
labels[i].Text = "Sample text";
labels[i].Size = new System.Drawing.Size(155, 51);
labels[i].BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
a = labels[i].Height + labels[i].Top;
but[i] = new Button();
but[i].Text = "-";
but[i].Location = new System.Drawing.Point(0, labels[i].Height + labels[i].Top);
but[i].Parent = panel1;
but[i].Size = new System.Drawing.Size(155, 10);
but[i].Click += new System.EventHandler(but_Click);
i++;
}
private void but[i]_Click(object sender, EventArgs e)
{
labels[i].Text = "Changed Text";
}
But apparently I can't put an array in an event handler, how should I do it then?

One way to do this is to make your method return a handler instead of being a handler:
private EventHandler but_Click(int i)
{
return (s, e) => labels[i].Text = "Changed Text";
}
And use it like:
but[i].Click += but_Click(i);
Or do it inline:
but[i].Click += (s, ea) => labels[i].Text = "Changed Text";
What's happening in either of these is some compiler magic to capture the i variable. It's equivalent to this (which is also a valid, if verbose, way to do it):
class MyWrapper {
private int i;
public MyWrapper(int i) {
this.i = i;
}
public void TheHandler(object sender, EventArgs e) {
// TODO: capture the object that owns `labels` also, or this won't work.
labels[i].Text = "Changed Text";
}
}
//call with
but[i].Click += new EventHandler(new MyWrapper(i).TheHandler);

You could add the array index to the button as Tag property, and then pull it back out in but_Click.
So, add
but[i].Tag = i;
to the button creation. And then change the event handler:
private void but_Click(object sender, EventArgs e)
{
int buttonIndex = (int)((Button)sender).Tag;
labels[buttonIndex].Text = "Changed Text";
}
Or put the event handler inline:
but[i].Click += (s,e) => { label[i].Text = "Changed Text"; }
Or another option using the Tag property, add:
but[i].Tag = label[i];
...
private void but_Click(object sender, EventArgs e)
{
Label label = (Label)((Button)sender).Tag;
label.Text = "Changed Text";
}
Advantage of this approach is you're not relying on keeping arrays in synch after the initial creation of the controls.

I guess this is self-explaining:
public void SomeMehthod()
{
Button btn1 = new Button();
Button btn2 = new Button();
Button btn3 = new Button();
// Your button-array
Button[] btns = new Button[]
{
btn1,
btn2,
btn3
};
foreach(Button btn in btns)
{
// For each button setup the same method to fire on click
btn.Click += new EventHandler(ButtonClicked);
}
}
private void ButtonClicked(Object sender, EventArgs e)
{
// This will fire on any button from the array
// You can switch on the name, or location or anything else
switch((sender as Button).Name)
{
case "btn1":
// Do something
break;
case "btn2":
// Do something
break;
case "btn3":
// Do something
break;
}
}
Or if your array is accessible globaly:
Button[] btns = new Button[5];
Label[] lbls = new Label[5];
private void ButtonClicked(Object sender, EventArgs e)
{
Button clicked = sender as Button;
int indexOfButton = btns.ToList().IndexOf(clicked);
// ..IndexOf() returns -1 if nothign is found
if(indexOfButton > 0)
{
lbls[indexOfButton].DoWhatYouWant...
}
}

Related

How to add buttons with independent click event

I want to add buttons and textboxes dynamically on runtime with each
button react differently.
ie newbutton1 linked with texbox1 ,newbutton2linked withtextbox2`
Right now any button just prints from the first to the last textbox
one after the other.
Also consider that I have a button1 & textbox1 already on the form for guides
Here is my code :
List<Button> buttons = new List<Button>();
List<TextBox> textboxes = new List<TextBox>();
int NumTextBox = 0;
void click(object sender, EventArgs e)
{
MessageBox.Show(textboxes[NumTextBox].Text);
NumTextBox++;
}
int x = 0;
int y = 0;
void AddClick(object sender, EventArgs e)
{
Button newButton = new Button();
buttons.Add(newButton);
newButton.Click += click;//
// newButton.Location.Y = button1.Location.Y + 20;
newButton.Location = new Point(button1.Location.X, button1.Location.Y+25+x);
x += 25;
this.Controls.Add(newButton);
TextBox newTextBox = new TextBox();
textboxes.Add(newTextBox);
// newTextBox.Click += click;
newTextBox.Location = new Point(textBox1.Location.X, textBox1.Location.Y+25+y);
y += 25;
this.Controls.Add(newTextBox);
}
you can have a class like mybutton that inherits from button class, in this new class you can have a property with textbox type . just like following code . and in your code when you want to Instantiated Button you can use list<mybutton> and set linkedTextbox property with a textbox.
public class myButton:Button
{
...
public TextBox linkedTextBox{set;get;}
}
and in your code you should write some thing like this :
list<myButton> buttons=new list<myButton>();
Textbox someTextBox=new TextBox();
buttons[0].linkedTextbox=someTextBox;
and in your event you can use:
((myButton)sender).linkedTextBox.text="Some thing";
Thank you everyone , I followed #Franck's answer .So WHAT CHANGED :
I've deleted the pre-made button1 & textbox1 and add them
programatically on the Form_load so that I can add them in the
Lists
A proof screenshot : http://prntscr.com/aprqxz
CODE:
List<Button> buttons = new List<Button>();
List<TextBox> textboxes = new List<TextBox>();
Button button1 = new Button();
TextBox textBox1 = new TextBox();
int x = 0;
int y = 0;
void click(object sender, EventArgs e)
{
var txt = textboxes[Convert.ToInt32(((Button)sender).Tag)].Text;
MessageBox.Show(txt.ToString());
}
void AddClick(object sender, EventArgs e)
{
Button newButton = new Button();
newButton.Click += click;
newButton.Location = new Point(button1.Location.X, button1.Location.Y+25+x);
x += 25;
newButton.Tag = buttons.Count;
this.Controls.Add(newButton);
buttons.Add(newButton);
//
TextBox newTextBox = new TextBox();
newTextBox.Location = new Point(textBox1.Location.X, textBox1.Location.Y+25+y);
y += 25;
this.Controls.Add(newTextBox);
textboxes.Add(newTextBox);
}
void MainFormLoad(object sender, EventArgs e)
{
button1.Click += click;
button1.Location = new Point(55, 48);
button1.Tag = buttons.Count;
this.Controls.Add(button1);
buttons.Add(button1);
//
textBox1.Location = new Point(137, 50);
this.Controls.Add(textBox1);
textboxes.Add(textBox1);
}
EDIT 1: As the counting starts from 0 I didn't added newButton.Tag = buttons.count+1; I added just newButton.Tag = buttons.count;

WPF: how to call method by setting tag of a dynamically created buttons

3 problems in my WPF(window phone) simple project. I have spent lot of time by solving it but no specific result found..
In my cs file I have Created bunch of dynamic buttons...I crated with for loop and set tags for each dynamic button.
My cs File code is here.
private void Grid_View_Btn_1_Click(object sender, System.Windows.RoutedEventArgs e)
{
//Grid ButtonsAddition
Dispatcher.BeginInvoke(() =>
{
string[] Trade = new string[] { "Portfolio Display", "Trade Idea Entry", "Trade Idea Monitor", "Historical Performance", "Intraday Performance", "Stock Performance" };
StackPanel panel = new StackPanel();
panel.Orientation = System.Windows.Controls.Orientation.Vertical;
//panel.HorizontalAlignment = System.Windows.HorizontalAlignment.Stretch;
//panel.VerticalAlignment = System.Windows.VerticalAlignment.Top;
int i;
for (i = 0; i < Trade.Length; i++)
{
Button btn = new Button() { Content = Trade[i] };
btn.Margin = new Thickness(0, -10, 0, -10);
var brush = new ImageBrush();
brush.ImageSource = new BitmapImage(new Uri("C:/Users/HafizArslan/Documents/Visual Studio 2012/Projects/AimPass/AimPass/Images/tabbar_btn_blue.png", UriKind.Relative));
btn.Background = brush;
btn.Width = 190;
btn.Height = 75;
btn.FontSize = 14;
btn.FontWeight = light;
btn.FontStretch = Fill;
btn.HorizontalAlignment = HorizontalAlignment.Center;
btn.VerticalAlignment = System.Windows.VerticalAlignment.Stretch;
// btn.CornerRadius = new CornerRadius(15);
btn.BorderThickness = new Thickness(1, 1, 1, 1);
btn.Tag = i.ToString();
btn.Click += new RoutedEventHandler(abc_click);
panel.Children.Add(btn);
}
grid.Children.Add(panel);
});
}
private void abc_click(object sender, EventArgs e)
{
}
There are 6 buttons creted.
the problem is I want to perform different actions with button...I have set Tags but I dont know how can I access an actions with buttons Tag..?
I mean I want something like this...!!
private void abc_click(object sender, EventArgs e)
{
// If(btn.Tag==1)
{
//Some Code Here
}
else
if(btn.Tag==2) {
//Perform other Function
}
} Etc.....?
and other problem is I have made a image brush..Assign exact path of image...for every created button background....But Image is not attached...
Kindly tell me about these 2 problems...
You have sender in handler, you can type cast sender to button and access Tag property from it:
private void abc_click(object sender, EventArgs e)
{
Button button = (Button)sender;
if(Convert.ToInt32(button.Tag) == 1)
{
.....
}
}
In your for loop, you can associate handler to the button.
Such as:
Button btn = new Button() { Content = Trade[i] };
btn.Margin = new Thickness(0, -10, 0, -10);
if(<something>)
btn.Click += YourEventHandler1;
if(<something2>)
btn.Click += YourEventHandler2;
If you want to access tag property, you need to cast the sender to Button, as so:
private void abc_click(object sender, EventArgs e)
{
var btn = (Button)sender;
}
you should go with this
var tag=((sender as Button).Tag).ToString();
////now use a switch
Switch(tag)
{
case "1":
//Action
break;
case "2":
//Acrion
break;
//more cases
}
hope this helps.
if for all created buttons the event is same then One approach could be to get the tag in the event like this
int tag=Convert.ToInt32((sender as Button).Tag);
now use a switch
switch(tag)
{
case 1:
//Action
break;
case 2:
//Acrion
break;
//more cases
}
hope this helps.

Assign MouseHover event to newly created Control

This is the new control add code part:
for (int i = 0; i < 1; i++)
{
var newLabel = new Label();
newLabel.Location = new Point(x, y);
newLabel.Size = new System.Drawing.Size(25, 25);
newLabel.Name = "lbl" + realpocsed.ToString();
if (value2== "Value2")
{
newLabel.MouseMove += new MouseEventHandler(this.MyControl_MouseMove);
newLabel.MouseDown += new MouseEventHandler(this.MyControl_MouseDown);
}
if (value== "Value1")
{
newLabel.MouseDown += new MouseEventHandler(this.MyControl_MouseHover);
}
panel1.Controls.Add(newLabel);
The MouseHover event look like this:
private void MyControl_MouseHover(object sender, MouseEventArgs e)
{
ToolTip ToolTip1 = new ToolTip();
ToolTip1.ShowAlways = true;
ToolTip1.Show("t", X); // X should be name of the newly created label
}
May I ask if is there any way to assign the newly created with name "lbl" + realpocsed.ToString() instead of X?
Thank you for your time.
You're assigning a MouseDown event to your MouseHover code, not sure you want that.
It should look like this:
newLabel.MouseHover += MyControl_MouseHover;
For your X, you would have to cast the sender:
ToolTip1.Show("Hover Message Here", (Label)sender);
You can't access any object by creating its name in string. The simple way to do that is to pass the object reference:
ToolTip1.Show("t", (sender as Label));
Inside for:
newLabel.MouseHover += delegate (object sender, EventArgs e)
{
ToolTip ToolTip1 = new ToolTip();
ToolTip1.ShowAlways = true;
ToolTip1.Show("t", newLabel);
};
Update:
if (value == "Value1")
{
newLabel.MouseHover += delegate (object sender, EventArgs e)
{
ToolTip ToolTip1 = new ToolTip();
ToolTip1.ShowAlways = true;
ToolTip1.Show("t", newLabel);
};
}

How create processing events for array of TextBox

I create array:
TextBox[] textarray = new TextBox[100];
Then in cycle set this params, all items array situated in uniformGrid1
textarray[i] = new TextBox();
textarray[i].Height = 30;
textarray[i].Width = 50;
uniformGrid1.Children.Add(textarray[i]);
How create events Click or DoubleClick that all items array?
Sorry my English.
public static void blah()
{
TextBox[] textarray = new TextBox[100];
List<TextBox> textBoxList = new List<TextBox>();
for (int i = 0; i < textarray.Length; i++)
{
textarray[i] = new TextBox();
textarray[i].Height = 30;
textarray[i].Width = 50;
// events registration
textarray[i].Click +=
new EventHandler(TextBoxFromArray_Click);
textarray[i].DoubleClick +=
new EventHandler(TextBoxFromArray_DoubleClick);
}
}
static void TextBoxFromArray_Click(object sender, EventArgs e)
{
// implement Event OnClick Here
}
static void TextBoxFromArray_DoubleClick(object sender, EventArgs e)
{
// implement Event OnDoubleClick Here
}
EDIT:
A better / recommended way of event registration as per #Aaronaugh: advice:
textarray[i].Click += TextBoxFromArray_Click;
textarray[i].DoubleClick += TextBoxFromArray_DoubleClick;
Just add in your click or double click event handler. For example, to trap double click events:
textarray[i] = new TextBox();
textarray[i].Height = 30;
textarray[i].Width = 50;
textarray[i].MouseDoubleClick += this.OnMouseDoubleClick;
uniformGrid1.Children.Add(textarray[i]);
For the above to work, you class will need a method like:
void OnMouseDoubleClick(object sender, MouseButtonEventArgs e)
{
// Do something
}
Create a click event handler and then use it to subscribe to the click events of your textboxes, like so:
textarray[i].Click += new EventHandler(textbox_Click);
...
void textbox_Click(object sender, EventArgs e)
{
// do something
}
If the actions you want to take are the same for each textbox, then one click handler will suffice.

C# create an array of controls

Is it possible to create an array of controls? Is there a way to get the index of a control if more than one of the controls in the array share the same event handler?
This is certainly possible to do. Sharing the event handler is fairly easy to do in this case because the Button which raised the event is sent as part of the event args. It will be the sender value and can be cast back to a Button
Here is some sample code
class Form1 : Form {
private Button[] _buttons;
public Form1(int count) {
_buttons = new Button[count];
for ( int i = 0; i < count; i++ ) {
var b = new Button();
b.Text = "Button" + i.ToString()
b.Click += new EventHandler(OnButtonClick);
_buttons[i] = b;
}
}
private void OnButtonClick(object sender, EventArgs e) {
var whichButton = (Button)sender;
...
}
}
Based on Kevins comment:
foreach(Button b in MyForm.Controls.OfType<Button>())
{
b.Click += Button_Click;
}
void Button_Click(object sender, EventArgs e)
{
Button clickedButton = sender as Button;
}

Categories

Resources