A button created inside code doesn't react to it's event - c#

I just started c# and encountered an error.
I use a button AddSquare to add a another button button and then using it I want to change a textbox ObjectName text on that button's click. But nothing happens.
public partial class Form1 : Form
{
const int UseFieldHeight = 580;
const int UseFieldWidth = 830;
const int UseFieldUperCoordinateX = 234;
const int UseFieldUperCoordinateY = 101;
Button button = new Button();
public Form1()
{
InitializeComponent();
}
private void AddSquare_Click(object sender, EventArgs e)
{
button.Size = new Size(50, 50);
button.BackColor = Color.Black;
button.BackgroundImageLayout = ImageLayout.Stretch;
button.Location = new Point(UseFieldUperCoordinateX, UseFieldUperCoordinateY);
button.Anchor = AnchorStyles.Left;
button.Visible = true;
InitializeComponent();
Controls.Add(button);
button.BringToFront();
button.Click += new EventHandler(button_Click);
}
void button_Click(object sender, EventArgs e)
{
ObjectName.Text = "TEST";
}
}
Is there something else I have to do?

I think it would work if you remove the InitializeComponent(); of your AddSquare_Click Event.

Related

How to Change backcolor of dynamically created button from another form

I have created a windows form application, where it adds some button when the form1 is loaded. I want to change the color of the form1 button when the form2 button is clicked
Point newLoc = new Point(20, 35);
int ButtonHeight = 0;
private void Form1_Load(object sender, EventArgs e)
{
for (int i = 1; i < 20; i++)
{
Button b = new Button
{
Name = "Btn" + i.ToString(),
Size = new Size(120, 60),
Location = newLoc, Text = i.ToString(),
BackColor = System.Drawing.Color.PaleGreen
};
i++;
if ((i % 10) == 0)
{
ButtonHeight = ButtonHeight + b.Height + 10;
newLoc = new Point(-110, 25 + ButtonHeight);
}
newLoc.Offset(b.Width + 10, 0);
Controls.Add(b);
}
}
public void Changecolor(Button b)
{
b.BackColor = System.Drawing.Color.Yellow;
}
private void Form1_Click(object sender, EventArgs e)
{
Form2 f2 = new Form2();
f2.Show();
}
//form2
private void button1_Click(object sender, EventArgs e)
{
Button b = new Button
{
Name = "Btn" + textBox1.Text
};
Form1 f1 = new Form1();
f1.Change_color(b);
}
if i type a number in form2.textbox and click form2.button. it should change the backcolor of form1.button with the name "Btn" + textBox1.Text
button.BackColor = Color.Red
where ever you want it to happen
When you call other function with new keyword, normally you cannot change their property.
You need to declare one object for opener form and set it's component like below (please change names for yours, it's going to be working for you):
//In form 2:
var frmName= (frmName)Application.OpenForms["frmName"];
frmName.Button1.BackColor=Color.Red
Edit: Yes you can access button which created dynamically but need to change access modifier to public.
// In form1:
public Button b =new Button();
private void button8_Click(object sender, EventArgs e)
{
b.Name = "btn";
b.Size = new Size(120, 60);
b.Text = "denemee";
b.BackColor = System.Drawing.Color.PaleGreen;
Controls.Add(b);
}

How to return a result if user doesn't click on message box

Background: I want to show a custom message box to the user with Yes/No buttons and if the user clicks each of these buttons I will return the result to the caller. Also, if the user doesn't show any reaction again I want to return a third result (using a Timer event). In a word, either after some time elapsed or after a button click the method (Display in my code) should return a value; and I want to wait for either of them to happen.
Problem: The UI looks frozen and only the Timer event triggers.
Code which will be used in the real project (with descent names!):
namespace MessageBox
{
public partial class Form2 : Form
{
public Form2()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
MyForm.Display();
}
}
public class MyForm : Form
{
public MyForm()
{
List<Button> _buttonCollection = new List<Button>();
FlowLayoutPanel _flpButtons = new FlowLayoutPanel();
Panel _plFooter = new Panel();
_plFooter.Dock = DockStyle.Bottom;
_plFooter.Padding = new Padding(5);
_plFooter.BackColor = Color.FromArgb(41, 47, 139);
_plFooter.Height = 75;
this.FormBorderStyle = FormBorderStyle.None;
this.BackColor = Color.FromArgb(20, 37, 105);
this.StartPosition = FormStartPosition.CenterScreen;
this.Padding = new Padding(3);
this.Width = 400;
_flpButtons.FlowDirection = FlowDirection.RightToLeft;
_flpButtons.Dock = DockStyle.Fill;
_plFooter.Controls.Add(_flpButtons);
this.Controls.Add(_plFooter);
Button btnYes = new Button();
btnYes.Click += ButtonClick;
btnYes.Text = "Yes";
Button btnNo = new Button();
btnNo.Click += ButtonClick;
btnNo.Text = "No";
_buttonCollection.Add(btnYes);
_buttonCollection.Add(btnNo);
foreach (Button btn in _buttonCollection)
{
btn.ForeColor = Color.FromArgb(170, 170, 170);
btn.Font = new System.Drawing.Font("Eurostile", 12, FontStyle.Bold);
btn.Padding = new Padding(3);
btn.FlatStyle = FlatStyle.Flat;
btn.Height = 60;
btn.Width = 150;
btn.FlatAppearance.BorderColor = Color.FromArgb(99, 99, 98);
_flpButtons.Controls.Add(btn);
}
}
static Task taskA;
private void ButtonClick(object sender, EventArgs e)
{
_event.Set();
Button btn = (Button)sender;
if (btn.Text == "Yes")
Result = 1;
else
{
Result = 2;
}
this.Close();
this.Dispose();
}
static AutoResetEvent _event = new AutoResetEvent(false);
private static MyForm form;
public static int Display()
{
form = new MyForm();
StartTimer();
form.Show();
_event.WaitOne();
form.Close();
form.Dispose();
return Result;
}
private static void StartTimer()
{
_timer = new System.Timers.Timer(10000);
_timer.Elapsed += SetEvent;
_timer.AutoReset = false;
_timer.Enabled = true;
}
private static System.Timers.Timer _timer;
public static int Result { get; set; }
private static void SetEvent(Object source, System.Timers.ElapsedEventArgs e)
{
_timer.Start();
Result = -1;
var timer = (System.Timers.Timer) source;
timer.Elapsed -= SetEvent;
_event.Set();
}
}
}
Note: I know the problem is that the UI control is created in a thread which is frozen but what's the solution?
Create a Dialog for MessageBox at the end of your process and show the alert you want to show the user.
You can look at the sources like and issue with Thread

How to dynamically create buttons and add events to them?

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...
}
}

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;

I am having trouble getting a URL to switch in this windows forms program

The program has a label, two radio buttons, and a set of generated buttons from A-Z. There are two URLs I would like to use that have a text list of names. When You click a lettered button, the program splits the text list and displays them in the label.
The two radio buttons are supposed to switch the URL being used. One URL has male first names, the other url has female first names. However, I am not sure how to get this to work...as I have it now, choosing the radio button does nothing... it will stay on whatever the first URL was.
using System;
using System.Windows.Forms;
using System.Net;
namespace IndexTable
{
public partial class frmIndex : Form
{
public frmIndex()
{
InitializeComponent();
}
private void Button_Click(object sender, EventArgs e)
{
Button btn = sender as Button; // Convert datatype
label1.Text = btn.Text + "\n"; ;
foreach (string c in name)
{
if (c != "" && c.Substring(0, 1) == btn.Text)
{
label1.Text += c + "\n";
//listBox1.Items.Add(c);
}
}
}
string[] name;
private void Form1_Load(object sender, EventArgs e)
{
int top = 10;
int left = 20;
int width = 30;
for (char i = 'A'; i <= 'M'; i++)
{
Button button = new Button();
button.Left = left;
button.Top = top;
button.Width = width;
button.Text = i.ToString();
this.Controls.Add(button);
button.Click += new System.EventHandler(this.Button_Click);
top += button.Height + 2;
}
left = 50;
top = 10;
for (char i = 'N'; i <= 'Z'; i++)
{
Button button = new Button();
button.Left = left;
button.Top = top;
button.Width = width;
button.Text = i.ToString();
this.Controls.Add(button);
button.Click += new System.EventHandler(this.Button_Click);
top += button.Height + 2;
}
WebClient wc = new WebClient();
string names = wc.DownloadString(url);
name = names.Split('\n');
}
private string url = "http://www.cs.cmu.edu/Groups/AI/areas/nlp/corpora/names/male.txt";
private void btnBoy_CheckedChanged(object sender, EventArgs e)
{
url = "http://scrapmaker.com/data/wordlists/names/male-names.txt";
}
private void btnGirl_CheckedChanged(object sender, EventArgs e)
{
url = "http://scrapmaker.com/data/wordlists/names/female-names.txt";
}
}
}
The CheckedChanged event fires whether the button becomes checked or becomes unchecked. Therefore you need to add a line of code to see what the current check state of the button is before responding:
private void btnBoy_CheckedChanged(object sender, EventArgs e)
{
if (btnBoy.Checked)
url = "http://scrapmaker.com/data/wordlists/names/male-names.txt";
}
EDIT: also you only use the url once, in the form load event, with the line
wc.DownloadString(url)
You'll need to add code to actually use the url again after you change it with the radiobuttons--either in the radiobutton event handler, or the other button event handler for instance.

Categories

Resources