C# - Dynamic buttons with dynamic data-entering - c#

I have a bit of an issue here.
I'm trying to create dynamic clickevents with variable data.
for(int i = 0; i < data.Devices.Length; i++)
{
Button _button = new Button();
_button.Size = new Size(100, 15);
_button.Text = data.Devices[i].Alias;
_button.Name = "textbox" + i.ToString();
_button.Location = new Point(x,y);
x += 110;
if(x > 1850)
{
y += 50;
x = 10;
}
if (data.Devices[i].OnlineState == "Online")
{
_button.BackColor = Color.Green;
}
else
{
_button.BackColor = Color.Red;
}
_button.Click += (Sender, args) =>
{
MessageBox.Show(data.Devices[i].Alias);
};
Controls.Add(_button);
}
The idea here is that I'll create buttons until length of the list is done (The list and position of these objects vary).
What I'm looking for is to make a bunch of buttons, and when you click on the button there should you'll open another screen with some statistics attached to that object.
Since the data will vary A LOT there is no way to hardcode each scenario, but instead I'm looking to do the same thing as you can do in Android, see below.
for (int i = 1; i <= 20; i++) {
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(
LinearLayout.LayoutParams.MATCH_PARENT,
LinearLayout.LayoutParams.WRAP_CONTENT);
Button btn = new Button(this);
btn.setId(i);
final int id_ = btn.getId();
btn.setText("button " + id_);
btn.setBackgroundColor(Color.rgb(70, 80, 90));
linear.addView(btn, params);
btn1 = ((Button) findViewById(id_));
btn1.setOnClickListener(new View.OnClickListener() {
public void onClick(View view) {
Toast.makeText(view.getContext(), "Button clicked index = " + id_, Toast.LENGTH_SHORT).show();
}
});
Is there any way I can achieve this?
Kind Regards.

I think the problem you are experiencing is regarding closures.
In your example you are adding the event handler with a delegate that's referencing the variable i which changes each loop iteration. So when the event handler is actually executed (when the button is clicked) i is out of scope.
You could do something like this:
private void Form1_Shown(object sender, EventArgs e)
{
var items = new[] { "Item One", "Item Two", "Item Three", "Item Four", "Item Five" };
for (int i = 0; i < items.Length; i++)
{
var btn = new Button
{
Text = $"Button {i + 1}",
Tag = items[i]
};
btn.Click += (object obj, EventArgs args)
=>
{
MessageBox.Show($"Hello. {((Button)obj).Tag}");
};
flowLayoutPanel1.Controls.Add(btn);
}
}
In your case - the button's tag can be set to data.Devices[i] - in other words it doesn't have to be a string it can be an object.

I start off by creating the buttons with the and placing them on the screen.
for (int i = 0; i < data.Devices.Length; i++){
Button _button = new Button();
_button.Size = new System.Drawing.Size(100, 55);
_button.Text = data.Devices[i].Alias;
_button.Name = "dynamicButton";
_button.FlatStyle = FlatStyle.Flat;
_button.Tag = data.Devices[i].Alias + "|" +
data.Devices[i].DeviceId + "|" +
data.Devices[i].LastSeen + "|" +
data.Devices[i].OnlineState + "|" +
data.Devices[i].Description + "|" +
data.Devices[i].RemotecontrolId;
_button.Location = new System.Drawing.Point(x, y);
x += 110;
if (x > 1850)
{
y += 60;
x = 30;
}
_button.Click += new EventHandler(bt_click);
Controls.Add(_button);
}
And then using the onclick event.
protected void bt_click(object sender, EventArgs e)
{
Button btn = sender as Button;
String[] information = btn.Tag.ToString().Split('|');
String present = "Namn: " + information[0]
+ "\nDeviceID: " + information[1]
+ "\nSenast uppe: " + information[2]
+ "\nStatus: " + information[3]
+ "\nEmail: " + information[4]
+ "\nTW-ID: " + information[5];
MessageBox.Show(present);
//DO THE THINGS WITH THE INFORMATION
}
And then to unload everything and eventually updating the status of the device.
for (int i = 0; i < 10; i++)
{
foreach (Control item in Controls.OfType<Control>())
{
if (item.Name == "dynamicButton")
{
Controls.Remove(item);
}
}
}
For some reason I have to loop that thing a couple of times, beacuse it won't delete them all, but instead deleting them in some pattern.
(only takes every other one each time)
I looped it 10 times for good measures.
It does exactly what I want it to do, and new devices gets added automaticly and removed devices dissapears just as fast.

Related

Dynamically generating Checkboxes but the event handler only works for the last one

Im trying to make dynamically checkboxes with a event handler but the event handler only works for the last one generated..
I have tried to change the position of my code. I have also tried to make more checboxes to se if that would make any difference.
for (int i = 0; i < appointments.TotalCount; i++) {
lstChckBox = new List<CheckBox>();
box = new CheckBox();
box.Tag = i;
box.Text = appointments.Items[i].Subject;
box.AutoSize = true;
box.Location = new Point(KalenderLbl.Location.X, KalenderLbl.Location.Y +
KalenderLbl.Height + 5 + (i * 25));
lstChckBox.Add(box);
box.CheckedChanged += new EventHandler(chck_CheckedChanged);
Controls.Add(box);
}
}
void chck_CheckedChanged(object sender, EventArgs e) {
foreach(CheckBox item in lstChckBox) {
if (item.Checked == true) {
Hide();
}
}
}
I want to know how to change the code so every checkbox have this event handler..
This code should do the trick as suggested by Dmitry Bychenko.
var lstChckBox = new List<CheckBox>( );
for (int i = 0; i < appointments.TotalCount; i++)
{
box = new CheckBox( );
box.Tag = i;
box.Text = appointments.Items[i].Subject;
box.AutoSize = true;
box.Location = new Point( KalenderLbl.Location.X, KalenderLbl.Location.Y + KalenderLbl.Height + 5 + ( i * 25 ) );
lstChckBox.Add( box );
box.CheckedChanged += new EventHandler( chck_CheckedChanged );
Controls.Add( box );
}
void chck_CheckedChanged( object sender, EventArgs e )
{
foreach (CheckBox item in lstChckBox)
{
if (item.Checked == true)
{
Hide( );
}
}
}
I would also suggest to shorten and simplify parts of your code, like.
var lstChckBox = new List<CheckBox>( );
var InitialYPosition = KalenderLbl.Location.Y + KalenderLbl.Height + 5;
for (int i = 0; i < appointments.TotalCount; i++)
{
box = new CheckBox( ) {
Tag = i,
Text = appointments.Items[i].Subject,
AutoSize = true,
Location = new Point( KalenderLbl.Location.X, InitialYPosition + ( i * 25 ) )
};
lstChckBox.Add( box );
box.CheckedChanged += new EventHandler( chck_CheckedChanged );
Controls.Add( box );
}
Minimizing the code and avoiding the using of box.Property to set some data that is going to be set none the less.

Get real time input from programmatically generated elements in C# form

How to get value of checkboxes (and the textbox upon change in text) in real time with form particulars that are all generated via code?
This following code produces a form upon button press, the form has checkboxes and a richtextbox. Ideally I want any interaction to have an effect, so if I paste in a grid of ones and zeros the checkboxes update, and once a checkbox gets click, the corresponding one or zero in the textarea will update (So that I can then copy the grid (matrix) out and into another program.
I know how to get the events using the visual studio GUI maker, but not from a programmatically created form like this.
private void begin_button_Click(object sender, EventArgs e)
{
// Build the child form
Form check_box = new Form();
check_box.FormBorderStyle = FormBorderStyle.FixedSingle;
// Get the values from the textboxes
int height = Convert.ToInt16(this.height_input.Text);
int width = Convert.ToInt16(this.width_input.Text);
// Set the dimensions of the form
check_box.Width = width * 15 + 40;
check_box.Height = ( height * 15 + 40 ) * 3;
// Build checkboxes for the checkbox form
CheckBox[] chk;
chk = new CheckBox[height * width];
int count = 0;
for (int i = 1; i <= height; i++)
{
for (int j = 1; j <= width; j++)
{
chk[count] = new CheckBox();
chk[count].Name = count.ToString();
chk[count].Width = 15; // because the default is 100px for text
chk[count].Height = 15;
chk[count].Location = new Point(j * 15, i * 15);
chk[count].CheckedChanged += new EventHandler(this.CheckedChanged);
check_box.Controls.Add(chk[count]);
count += 1;
//Console.WriteLine(" i: " + i + " j: " + j + " Count: " + count);
}
}
RichTextBox output_area;
output_area = new RichTextBox();
output_area.Location = new Point(chk[0].Location.X, chk[count-1].Location.Y + 30);
check_box.Controls.Add(output_area);
output_area.Text = "hello world\n1,1,1,1,1,1,1,1,1\n0,0,0,0,0,1,0,1\nthese ones and zeros are meant to update in real time!";
output_area.Width = check_box.Width - 40;
output_area.Height = check_box.Height / 2;
// Run the form
check_box.ShowDialog();
}
EDIT:
I have added the event handler and it's working, however I can't access the checkbox form, only the main form.
private void CheckedChanged(object sender, EventArgs e)
{
//throw new NotImplementedException();
CheckBox x = (CheckBox)sender;
Console.WriteLine(x);
Console.WriteLine(x.Name.ToString());
}
Have a look at the .Designer file that the form designer generates for you!
Anyway, in your loop, try something like this:
chk[count].CheckedChanged += MyFancyHandler;
And the handler itself will look just like a normal handler:
private void MyFancyHandler( object sender, EventArgs e )
{
// ...
}
Also notice that the sender argument there will contain a reference to whichever checkbox/control the event refers to.
Below code updates matrix text in the rich text box when check box check state changed.
RichTextBox output_area;
CheckBox[] chk;
Size MatrixSize;
private void begin_button_Click()
{
// Build the child form
Form check_box = new Form();
check_box.FormBorderStyle = FormBorderStyle.FixedSingle;
check_box.StartPosition = FormStartPosition.CenterScreen;
// Get the values from the textboxes
int height = Convert.ToInt16("10");
int width = Convert.ToInt16("7");
MatrixSize = new Size(width, height);
// Set the dimensions of the form
check_box.Width = width * 15 + 40;
check_box.Height = (height * 15 + 40) * 3;
// Build checkboxes for the checkbox form
chk = new CheckBox[height * width];
int count = 0;
for (int i = 1; i <= height; i++)
{
for (int j = 1; j <= width; j++)
{
chk[count] = new CheckBox();
chk[count].Name = count.ToString();
chk[count].Width = 15; // because the default is 100px for text
chk[count].Height = 15;
chk[count].Location = new Point(j * 15, i * 15);
check_box.Controls.Add(chk[count]);
chk[count].CheckedChanged += new EventHandler(CheckBox1_CheckedChanged);
count += 1;
//Console.WriteLine(" i: " + i + " j: " + j + " Count: " + count);
}
}
output_area = new RichTextBox();
output_area.Location = new Point(chk[0].Location.X, chk[count - 1].Location.Y + 30);
check_box.Controls.Add(output_area);
output_area.Text = "hello world\n1,1,1,1,1,1,1,1,1\n0,0,0,0,0,1,0,1\nthese ones and zeros are meant to update in real time!";
output_area.Width = check_box.Width - 40;
output_area.Height = check_box.Height / 2;
// Run the form
check_box.ShowDialog();
}
private void CheckBox1_CheckedChanged(Object sender, EventArgs e)
{
CheckBox c = (CheckBox)sender;
Debug.WriteLine(c.Name);
StringBuilder sb = new StringBuilder();
int count = 0;
for (int i = 1; i <= MatrixSize.Height; i++)
{
for (int j = 1; j <= MatrixSize.Width; j++)
{
if (chk[count].Checked)
{
sb.Append("1,");
}
else
{
sb.Append("0,");
}
count += 1;
}
sb.Append("\r\n");
}
output_area.Text = sb.ToString();
}

How can i change label text from different button in C#

I descripted my problem in script comments. Function GraphicClassStructure is only for create buttons and label. But mainly function is plusButton_click. I need that if i clicked on first plus button so i need change text for first added label.
Script: (Problem is here: plusButton_click, i descripted problem to case)
class GraphicClassStructure : GraphicPosition
{
// Button
public Button plus;
public PictureBox classBackround = new PictureBox();
// Label
Label points;
public void CreateSpellsButton()
{
for (int j = 0; j < 3; j++)
{
for (int i = 0; i < 10; i++)
{
plus = new Button();
points = new Label();
switch (j)
{
case 0:
points.Location = Location[1][i];
points.Location = new Point(points.Location.X + 8, points.Location.Y + 45);
plus.Location = Location[2][i];
break;
case 1:
plus.Location = Location[2][i];
plus.Location = new Point(plus.Location.X + 205, plus.Location.Y);
points.Location = Location[1][i];
points.Location = new Point(points.Location.X + 213, points.Location.Y + 45);
break;
case 2:
plus.Location = Location[2][i];
plus.Location = new Point(plus.Location.X + 410, plus.Location.Y);
points.Location = Location[1][i];
points.Location = new Point(points.Location.X + 418, points.Location.Y + 45);
break;
}
// Labels for point
points.BackColor = Color.Transparent;
points.ForeColor = Color.FromArgb(((int)(((byte)(193)))), ((int)(((byte)(196)))), ((int)(((byte)(181)))));
points.BackgroundImageLayout = ImageLayout.Stretch;
points.FlatStyle = FlatStyle.Flat;
points.Name = "points";
points.Name = spells.Name + i.ToString() + "_" + j.ToString();
if (i >= 6)
points.Text = "0 / 2";
else
points.Text = "0 / 1";
points.VisibleChanged += new EventHandler(classUniqueButtons_VisibleChanged);
// Plus
plus.BackColor = Color.Transparent;
plus.BackgroundImage = BuildResource.plus;
plus.BackgroundImageLayout = ImageLayout.Stretch;
plus.FlatAppearance.BorderSize = 0;
plus.FlatAppearance.MouseDownBackColor = Color.Transparent;
plus.FlatAppearance.MouseOverBackColor = Color.Transparent;
plus.FlatStyle = FlatStyle.Flat;
plus.Name = "plus";
plus.Size = Size[0][9];
plus.UseVisualStyleBackColor = false;
plus.Name = plus.Name + i.ToString() + "_" + j.ToString();
plus.Click += new EventHandler(plusButton_click);
plus.VisibleChanged += new EventHandler(classUniqueButtons_VisibleChanged);
plus.MouseEnter += new EventHandler(this.classButton_MouseEnter);
plus.MouseLeave += new EventHandler(this.classButton_MouseLeave);
classBackround.Controls.Add(plus);
classBackround.Controls.Add(points);
}
}
}
private void plusButton_click(object sender, EventArgs e)
{
var currentButton = sender as Button;
var name = currentButton.Name;
switch (name)
{
// Ultimate
case "plus0_0":
// If i clicked on this button so i need change text for first added label
// I try this, but it changed only last added labe
points.Text = "test";
break;
case "plus0_1":
// If i clicked on this button so i need change text for second added label
break;
}
}
private void minusButton_click(object sender, EventArgs e)
{
var currentButton = sender as Button;
var name = currentButton.Name;
switch (name)
{
// Ultimate
case "minus0_0":
// If i clicked on this button so i need change text for first added label
// I try this, but it changed only last added labe
points.Text = "test";
break;
case "minus0_1":
// If i clicked on this button so i need change text for second added label
break;
}
}
}
very simple to do here what you need
for (int j = 0; j < 3; j++)
{
for (int i = 0; i < 10; i++)
{
plus = new Button();
//tag is an object and can be used to reference any other object
plus.Tag = new Label();
and to retrieve what you need do this
private void plusButton_click(object sender, EventArgs e)
{
var currentButton = sender as Button;
var name = currentButton.Name;
switch (name)
{
// Ultimate
case "plus0_0":
(currentButton.Tag as Label).Text = "test";
break;
case "plus0_1":
(currentButton.Tag as Label).Text ="test2"
break;
}
}
You are using a global reference to the label which you have overwritten in each iteration of your loop. Therefore it always references the last label. Since you always add the label after the button and have the reference to the button you can probably get the correct label like this:
Label pointsLabel = (Label)classBackround.Controls[classBackround.Controls.IndexOf(currentButton) + 1]

Button Array - which one is pressed? c#

I tried to dynamically create an array of buttons and i cant quite figure out how i can let a function know which button actually was pressed.. i tried it this way but it does not seem to work out. Any ideas?
public void game_setup(int columns, int rows, int mines)
{
//game_destroy();
//Set Window Size
this.Height = 50 + Options.y_ini + rows * (Options.size + Options.space);
this.Width = 20 + 2 * Options.x_ini + columns * (Options.size + Options.space);
//Setup the playing field
Button[,] field = new Button[columns,rows];
for (int i = 0; i < columns; i++)
{
for (int j = 0; j < rows; j++)
{
field[i, j] = new Button();
//Button Size
field[i, j].Width = Options.size;
field[i, j].Height = Options.size;
//Button Position
int x = Options.x_ini + i * (Options.size + Options.space);
int y = Options.y_ini + j * (Options.size + Options.space);
field[i, j].Location = new Point(x, y);
//Event Handler
int send_i = i;
int send_j = j;
field[i, j].Click += (sender, args) =>
{
field_Click(send_i, send_j);
};
//Add the Button to the GameBoard
Controls.Add(field[i, j]);
}
}
//Distribute the Mines
//...
}
public void field_Click(int x, int y)
{
MessageBox.Show("X:" + x + " Y:" + y);
field[1, 2].Text = "hi";
}
Change your event handler to pass on the sender parameter. This is a reference to the button that was clicked.
field[i, j].Click += (sender, args) =>
{
field_Click(sender, send_i, send_j);
};
public void field_Click(object sender, int x, int y)
{
Button btn = sender as Button;
MessageBox.Show(btn.Name + "X:" + x + " Y:" + y);
field[x, y].Text = "hi";
}
field[i, j].Tag = new Point(send_i, send_j);
field[i, j].Click += (sender, args) => {
Button button = sender as Button;
Point p = (Point) button.Tag;
field_Click(p.X, p.Y);
};
NOTE: the point is you can access the actual clicked Button via the sender, just cast it to Button and you can do everything with the clicked Button.
field[i, j].Name = i +j';
field[i, j].Click += (sender, args) =>
{
field_Click(sender, send_i, send_j);
};
public void field_Click(object theButton, int x, int y)
{
var currentButton = (Button) sender;
if ( currentButton.Name == YOUR CODE HERE IF YOU WANT TO CHECK SOMETHING)
{
MessageBox.Show("X:" + x + " Y:" + y);
field[1, 2].Text = "hi";
}
}
What you want to do is just have X and Y when the click happen. You don't need to do much.
First use a very standard click event.
then replace this :
int send_i = i;
int send_j = j;
field[i, j].Click += (sender, args) =>
{
field_Click(send_i, send_j);
};
With this
field[i, j].Tag = i.ToString() + "|" + j.ToString();
field[i, j].Click += new EventHandler(field_Click);
Now change the event handler to be the following
private void field_Click(object sender, EventArgs e)
{
string[] sSplitTag = ((Button)sender).Tag.ToString().Split('|');
int i = Convert.ToInt32(sSplitTag[0]);
int j = Convert.ToInt32(sSplitTag[1]);
}
Always try to use the tag to know detail about who your control is. it's what this property is made for... tagging you control so you can recognize him when you see him again.

How to add buttons dynamically to my form?

I want to create 10 buttons on my form when I click on button1. No error with this code below but it doesnt work either.
private void button1_Click(object sender, EventArgs e)
{
List<Button> buttons = new List<Button>();
for (int i = 0; i < buttons.Capacity; i++)
{
this.Controls.Add(buttons[i]);
}
}
You aren't creating any buttons, you just have an empty list.
You can forget the list and just create the buttons in the loop.
private void button1_Click(object sender, EventArgs e)
{
int top = 50;
int left = 100;
for (int i = 0; i < 10; i++)
{
Button button = new Button();
button.Left = left;
button.Top = top;
this.Controls.Add(button);
top += button.Height + 2;
}
}
It doesn't work because the list is empty. Try this:
private void button1_Click(object sender, EventArgs e)
{
List<Button> buttons = new List<Button>();
for (int i = 0; i < 10; i++)
{
Button newButton = new Button();
buttons.Add(newButton);
this.Controls.Add(newButton);
}
}
You could do something like this:
Point newLoc = new Point(5,5); // Set whatever you want for initial location
for(int i=0; i < 10; ++i)
{
Button b = new Button();
b.Size = new Size(10, 50);
b.Location = newLoc;
newLoc.Offset(0, b.Height + 5);
Controls.Add(b);
}
If you want them to layout in any sort of reasonable fashion it would be better to add them to one of the layout panels (i.e. FlowLayoutPanel) or to align them yourself.
Two problems- List is empty. You need to add some buttons to the list first. Second problem: You can't add buttons to "this". "This" is not referencing what you think, I think. Change this to reference a Panel for instance.
//Assume you have on your .aspx page:
<asp:Panel ID="Panel_Controls" runat="server"></asp:Panel>
private void button1_Click(object sender, EventArgs e)
{
List<Button> buttons = new List<Button>();
for (int i = 0; i < buttons.Capacity; i++)
{
Panel_Controls.Controls.Add(buttons[i]);
}
}
use button array like this.it will create 3 dynamic buttons bcoz h variable has value of 3
private void button1_Click(object sender, EventArgs e)
{
int h =3;
Button[] buttonArray = new Button[8];
for (int i = 0; i <= h-1; i++)
{
buttonArray[i] = new Button();
buttonArray[i].Size = new Size(20, 43);
buttonArray[i].Name= ""+i+"";
buttonArray[i].Click += button_Click;//function
buttonArray[i].Location = new Point(40, 20 + (i * 20));
panel1.Controls.Add(buttonArray[i]);
} }
I had the same doubt and came up with the following contribution:
int height = this.Size.Height;
int width = this.Size.Width;
int widthOffset = 10;
int heightOffset = 10;
int btnWidth = 100; // Button Widht
int btnHeight = 40; // Button Height
for (int i = 0; i < 50; ++i)
{
if ((widthOffset + btnWidth) >= width)
{
widthOffset = 10;
heightOffset = heightOffset + btnHeight
var button = new Button();
button.Size = new Size(btnWidth, btnHeight);
button.Name = "" + i + "";
button.Text = "" + i + "";
//button.Click += button_Click; // Button Click Event
button.Location = new Point(widthOffset, heightOffset);
Controls.Add(button);
widthOffset = widthOffset + (btnWidth);
}
else
{
var button = new Button();
button.Size = new Size(btnWidth, btnHeight);
button.Name = "" + i + "";
button.Text = "" + i + "";
//button.Click += button_Click; // Button Click Event
button.Location = new Point(widthOffset, heightOffset);
Controls.Add(button);
widthOffset = widthOffset + (btnWidth);
}
}
Expected Behaviour:
This will generate the buttons dinamically and using the current window size, "break a line" when the button exceeds the right margin of your window.
First, you aren't actually creating 10 buttons. Second, you need to set the location of each button, or they will appear on top of each other. This will do the trick:
for (int i = 0; i < 10; ++i)
{
var button = new Button();
button.Location = new Point(button.Width * i + 4, 0);
Controls.Add(button);
}
You can't add a Button to an empty list without creating a new instance of that Button.
You are missing the
Button newButton = new Button();
in your code plus get rid of the .Capacity

Categories