l've 10 ten button on my forms ( 0 to 9) to simulate a calculator
All my buttons are named like this btnCalc0,btnCalc1,btnCalc2,etc...
I want to create an array or list of these buttons to handle event but it's doesn't work because btnCalc doesnt exist(btnCalc+x).
List<Button> lstBtnCalc = new List<Button>();
for (int x = 0; x < 10; x++)
{
lstBtnCalc.Add(btnCalc+x));
}
private void myClick(object sender, EventArgs e)
{
int index = lstBtnCalc.IndexOf(sender as Button);
}
You could populate your array with a loop (See ASh's answer). However, in doing so, you make the code harder to read. The primary test of good code is readable code, so avoid "clever" solutions and keep it simple. In this case, a simple, easy to read and maintain, way is:
List<Button> lstBtnCalc = new List<Button>
{
btnCalc0, btnCalc1, btnCalc2, btnCalc3, btnCalc4,
btnCalc5, btnCalc6, btnCalc7, btnCalc8, btnCalc9
}
You can use Find method:
List<Button> lstBtnCalc = new List<Button>();
for (int x = 0; x < 10; x++)
{
var buttonName = string.Format("btnCalc{0}",x);
var button = this.Controls.Find(buttonName);
if (button != null)
{
lstBtnCalc.Add(button);
}
}
Try this
public partial class Form1 : Form
{
List<Button> lstBtnCalc = null;
public Form1()
{
InitializeComponent();
lstBtnCalc = new List<Button>() { button1, button2, button3, button4 };
}
}
a bit fluent:
List<Button> lstBtnCalc = this.Controls.OfType<Button>().Where(a => a.Name.StartsWith("btnCacl")).ToList();
Related
I am designing an application in C# Winforms (for the first time). I've designed several applications in C++ in the past, and am having difficulty converting some of my C++-CLI functions to C#.
I have 5 buttons along a side bar that toggles the visibility of the button's corresponding panel per button click. In order to do this, I set the visibility of all other panels to false. In order to achieve this in C++-CLI, I've done the following:
private: System::Void panels_Click(System::Object^ sender, System::EventArgs^ e) {
System::Windows::Forms::Button ^ currentbutton = (System::Windows::Forms::Button ^) sender;
array < Panel ^ > ^ objects = { panel1, panel2, panel3, panel4, panel5, panel6};
array < Button ^ > ^ buttons = { button1, button2, button3, button4, button5, button6 };
for (int i = 0; i < 6; i++) {
if (buttons[i]->Equals(currentbutton)) {
objects[i]->Visible = true;
}
else objects[i]->Visible = false;
}
}
The issue I am having is with the " array Panel ^" portion, as I can not find an equivalent in C#. Any help is appreciated.
Arrays are declared in C# using TypeName[].
Panel[] objects = { panel1, panel2, panel3, panel4, panel5, panel6 };
Button[] buttons = { button1, button2, button3, button4, button5, button6 };
You can cast the Controls collection to a List<Control>, and then access the control name for comparison. The Cast<T>() method is a linq extension method, so you'll have to add using System.Linq; to your namespace:
private void panels_Click(object sender, EventArgs e)
{
List<string> panelNames = new List<string>
{"panel1", "panel2", "panel3", "panel4", "panel5", "panel6"};
List<string> buttonNames = new List<string>
{"button1", "button2", "button3", "button4", "button5", "button6"};
List<Control> panels = this.Controls.Cast<Control>()
.Where(ctrl => panelNames.Contains(ctrl.Name)).ToList();
List<Control> buttons = this.Controls.Cast<Control>()
.Where(ctrl => buttonNames.Contains(ctrl.Name)).ToList();
Button thisButton = sender as Button;
for (int i = 0; i < buttons.Count; i++)
{
if (i < panels.Count) panels[i].Visible = buttons[i] == thisButton;
}
}
This question already has answers here:
Pass extra parameters to an event handler?
(10 answers)
Closed 2 years ago.
I use the loop for a two dimensions array of buttons. I don't know how to know exactly which buttons in array were clicked or not
Here are my code:
for (int i = 0; i < 100 ; i++)
{
for (int j=0 ; j< 100; i++)
{
arrButton[i, j] = new Button();
arrButton[i,j].Size = new Size(size1button, size1button);
arrButton[i,j].Location = new Point(j*size1button, i*size1button);
arrButton.Click += new EventHandler(arrButton_Click);
}
}
Can I use parameters i, j for mouse click event like:
private void arrButton_Click(object sender, EventArgs e, int i, int j)
{
//my idea : add i, j to another int[,] array to keep track of buttons which were clicked
}
If this exits, how to write it correctly? Or can you recommend or method to know exactly where the button was clicked in array ?
Try this
public class Indeces
{
public int IndexI { get; set; }
public int IndexJ { get; set; }
}
Now in loop set Tag
for (int i = 0; i < 100 ; i++)
{
for (int j=0 ; j< 100; i++)
{
arrButton[i, j] = new Button();
arrButton[i,j].Size = new Size(size1button, size1button);
arrButton[i,j].Location = new Point(j*size1button, i*size1button);
arrButton.Click += new EventHandler(arrButton_Click);
arrButton.Tag = new Indeces {IndexI = i,IndexJ = j};
}
}
Get values from Tag here as
private void arrButton_Click(object sender, EventArgs e)
{
var button = sender as Button;
var indeces = (Indeces) button.Tag;//get indeces here
var i = indeces.IndexI;
var j = indeces.IndexJ;
}
You cannot change the EventHandler signature to include your i and j.
However, you can get that information from what is already passed to the arrButton_Click method. Since you set the location of each button as new Point(j*size1button, i*size1button), you can get each i and j component back by dividing the location of your button by size1button.
To get that location, you can use the sender, which is your Button (a cast is necessary):
private void arrButton_Click(object sender, EventArgs e)
{
Button btnClicked = (Button) sender;
int i = btnClicked.Location.Y / size1button;
int j = btnClicked.Location.X / size1button;
}
Also, the code you're currently using to create the buttons have a couple errors.
First, you're never incrementing j; the second loop does i++.
Second, if you want your buttons to appear, you have to add them to your Form's Controls.
Finally, I don't think you can have 10 000 active buttons on your form, try a lower number, like 25.
So the corrected code would look like:
for (int i = 0; i < 5; i++)
{
for (int j = 0; j < 5; j++)
{
arrButton[i, j] = new Button();
arrButton[i, j].Size = new Size(size1button, size1button);
arrButton[i, j].Location = new Point(j*size1button, i*size1button);
arrButton[i, j].Click += arrButton_Click;
Controls.Add(arrButton[i,j]);
}
}
You can also notice that I removed your declaration of new EventHandler, which was redundant.
If you are only interested in Location then whats wrong with this? -
private void arrButton_Click(object sender, EventArgs e)
{
var button = sender as Button;
//now use button.Location
}
But if you want more data other than just location. Here is an example
Use a custom button class -
public class CustomButton<T> : Button {
public T Data{get;set;}
public CustomButton(T data){
this.Data = data; //i didn't compile it, so data type might mismatch.
}
}
Then use this button class -
for (int i = 0; i < 100 ; i++)
{
for (int j=0 ; j< 100; i++)
{
arrButton[i, j] = new CustomButton<T> (...some data);
arrButton[i,j].Size = new Size(size1button, size1button);
arrButton[i,j].Location = new Point(j*size1button, i*size1button);
arrButton.Click += new EventHandler(arrButton_Click);
}
}
In the event handler Cast to CustomButton and voila, there is your location -
private void arrButton_Click(object sender, EventArgs e)
{
var cButton = sender as CustomButton<T>;
// cButton.Datais your point. Have fun
}
BTW, you cannot change the default signature of event handlers, if you want you have to implement your own event/delegate.
I have written a code that create buttons dynamically. The code works well, and create controls when I click on a button. Now the next task is, I want to define click event for these dynamically created controls. How can I do this ? Below is the code, Please modify this code and paste in a reply, so that I can understand easily.
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
// create controls dynamically on form
int n = 4;
private void btnDisplay_Click_1(object sender, EventArgs e)
{
Button[] button = new Button[n];
int previousButtonPositionY;
int previousButtonHeight;
for (int i = 0; i < n; i++)
{
button[i] = new Button();
button[i].Name = "btnButton" + i;
button[i].Text = "btnButton" + i;
if (i > 0)
{
previousButtonPositionY = button[i - 1].Location.Y;
previousButtonHeight = button[i - 1].Height;
}
else
{
previousButtonPositionY = 50;
previousButtonHeight = 0;
}
button[i].Location = new Point(0, previousButtonPositionY + previousButtonHeight);
}
for (int i = 0; i < n; i++)
{
panel1.Controls.Add(button[i]);
}
}
}
After you have initialized your button you can add an onclick event to it with
button[i].Click += new EventHandler(button_Click);
More here: http://msdn.microsoft.com/en-us/library/ms743596%28v=vs.110%29.aspx
Hi I have a small winforms program that will soon develop into something more. The program has 2 panels panel1 and panel2 these panels are populated dynamically with some form controls. the first panel is populated with combo-boxes and the second with a grid of buttons. What I want to achieve is to be able to disable the right button depending on what the user selects from the combobox. Each column of the grid represent a day of the week and the combobox will be used to disable the wanted day by selecting it from the list if you like.
To do this statically is straight forward, however my program will soon expand so that it can handle a large database so that's why I am doing this dynamically. Basically this is where I'm stuck at the moment I want to simply disable the right button.
Below is the interface that i have so far:
And this is my code if any help:
public Form1()
{
InitializeComponent();
}
Button[] btn = new Button[2];
ComboBox[] cmb = new ComboBox[1];
private void Form1_Load(object sender, EventArgs e)
{
placeRows();
}
public void createColumns(int s)
{
for (int i = 0; i < btn.Length; ++i)
{
btn[i] = new Button();
btn[i].SetBounds(40 * i, s, 35, 35);
btn[i].Text = Convert.ToString(i);
panel1.Controls.Add(btn[i]);
}
for (int i = 0; i < cmb.Length; ++i)
{
cmb[i] = new ComboBox();
cmb[i].SelectedIndexChanged += new EventHandler(cmb_SelectedIndexChanged);
cmb[i].Text = "Disable";
cmb[i].Items.Add("Monday");
cmb[i].Items.Add("Tuesday");
cmb[i].SetBounds(40 * i, s, 70, 70);
panel2.Controls.Add(cmb[i]);
}
}
void cmb_SelectedIndexChanged(object sender, EventArgs e)
{
ComboBox senderCmb = (ComboBox)sender;
if (senderCmb.SelectedIndex == 1)
{
//MessageBox.Show("Tuesday");
btn[1].Enabled = false;
}
}
public void placeRows()
{
for (int i = 0; i < 80; i = i + 40)
{
createColumns(i);
}
}
}
Alternative 1
Every control has a Tag property.
You can set the Tag property of your buttons to represent the column they are in.
When a selection is made in the combo box, simply search through all buttons, and enable or disable the button based on whether each button's Tag property matches the selected text in the combo box.
Alternative 2
Create a
Dictionary<string, List<Button>> buttonMap;
where the key is the value representing the column ("Tuesday") and the value is a list of buttons with that tag. When creating the buttons initially, also populate that dictionary.
If you go with Alternative 2, you'll have to remember the previously selected value of the checkbox so you can re-enable buttons that are no longer disabled.
If you have lots of buttons, you may find that Alternative 2 is noticeably faster.
UPDATE
Here's a complete working sample of Alternative 1.
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
const int ROWS = 2;
const int COLS = 2;
Button[,] btn = new Button[ROWS,COLS];
ComboBox[] cmb = new ComboBox[ROWS];
private void Form1_Load(object sender, EventArgs e)
{
placeRows();
}
private readonly string[] cbTexts = new string[] { "Monday", "Tuesday" };
public void createColumns(int rowIndex)
{
int s = rowIndex * 40;
// Your original code kept overwriting btn[i] for each column. You need a 2-D array
// indexed by the row and column
for (int colIndex = 0; colIndex < COLS; colIndex++)
{
btn[rowIndex, colIndex] = new Button();
btn[rowIndex, colIndex].SetBounds(40 * colIndex, s, 35, 35);
btn[rowIndex, colIndex].Text = Convert.ToString(colIndex);
btn[rowIndex, colIndex].Tag = cbTexts[colIndex];
panel1.Controls.Add(btn[rowIndex, colIndex]);
}
cmb[rowIndex] = new ComboBox();
cmb[rowIndex].SelectedIndexChanged += new EventHandler(cmb_SelectedIndexChanged);
cmb[rowIndex].Text = "Disable";
foreach (string cbText in cbTexts)
{
cmb[rowIndex].Items.Add(cbText);
}
cmb[rowIndex].SetBounds(40, s, 70, 70);
cmb[rowIndex].Tag = rowIndex; // Store the row index so we know which buttons to affect
panel2.Controls.Add(cmb[rowIndex]);
}
void cmb_SelectedIndexChanged(object sender, EventArgs e)
{
ComboBox senderCmb = (ComboBox)sender;
int row = (int)senderCmb.Tag;
for (int col = 0; col < COLS; col++)
{
Button b = btn[row, col];
// These three lines can be combined to one. I broke it out
// just to highlight what is happening.
string text = ((string)b.Tag);
bool match = text == senderCmb.SelectedItem.ToString();
b.Enabled = match;
}
}
public void placeRows()
{
for (int rowIndex = 0; rowIndex < 2; rowIndex++)
{
createColumns(rowIndex);
}
}
}
I know how to create button during runtime.
Button button1 = new Button();
button1.Location = new Point(20,10);
button1.Text = "Click Me";
// adding to groupBox1
groupBox1.Controls.Add(button1);
But the problem is i want to add multiple buttons like this..
for(int i = 1; i < 30; i++) {
Button button[i] = new Button();
// Button customization here...
...
groupBox1.Controls.Add(button[i]);
}
The code above is false code. How can I make this happen true in C#.net? i want to create multiple buttons with button name, button1, button2, button3, button4, .... button30;
You can't declare extra variables at execution time in C# - but you really don't want to anyway, as you wouldn't be able to access them dynamically afterwards. Just create an array:
// buttons would be declared as Button[] as a member variable
buttons = new Button[30];
for(int i = 0; i < buttons.Length; i++) {
buttons[i] = new Button();
// Button customization here...
...
groupBox1.Controls.Add(buttons[i]);
}
Alternatively, use a List<Button>, which will certainly be more convenient if you don't know how many buttons you need beforehand. (See the obligatory "arrays considered somewhat harmful" blog post.)
Of course, if you don't actually need to get at the buttons later, don't bother assigning them to anything visible outside the loop:
for(int i = 0; i < 30; i++) {
Button button = new Button();
// Button customization here...
...
groupBox1.Controls.Add(button);
}
You need to think about what information you need access to when... and how you want to access it. If you logically have a collection of buttons, you should use a collection type variable (like a list or an array).
Frankly I think it's one of the curses of the VS designers that you end up with horrible names such as "groupBox1" which carry no information beyond what's already in the type declaration, and encourage developers to think of collections of controls via individually-named variables. That's just me being grumpy though :)
Try this
for(int i = 1; i < 30; i++) {
Button button = new Button();
// Button customization here...
button.Name = "Button" + i.ToString();
groupBox1.Controls.Add(button);
}
You seem like you're almost on the right track:
// in form class
Button[] m_newButtons = new Button[30];
// in your trigger function
for(int i = 0; i < 30; ++i)
{
m_newButtons[i] = new Button();
// ...
groupBox1.Controls.Add(m_newButtons[i]);
}
If you try and do this more than once you may have to remove the old buttons from the control before adding the new ones.
buttons = new Button[30];
for(int i = 0; i < buttons.Length; i++) {
buttons[i] = new Button();
groupBox1.Controls.Add(buttons[i]);
}
this code will work but button will be added one over other so set location also
buttons = new Button[30];
for(int i = 0; i < buttons.Length; i++)
{
buttons[i] = new Button();
Point p=new Point(xvalue,yvalue);
buttons[i].Location = p;
groupBox1.Controls.Add(buttons[i]);
}
one thing you want to remember increment the x or y position by which you want to display it
Try this one out, I have just learned it myself:
public partial class Form1 : Form
{
Button[] btn = new Button[12];// <--------<<<Button Array
public Form1()
{
InitializeComponent();
}
private void Form1_Load (object sender, EventArgs e)
{
for (int i = 0; i < 12; i++)
{
btn[i] = new Button ( );
this.flowLayoutPanel1.Controls.Add(btn[i]);
}
}
// double click on the flow layoutPannel initiates this code
private void flowLayoutPanel1_Paint(object sender, PaintEventArgs e)
{
}
}