How to pass an index of a button to an EventHandler? - c#

Good to know is that I just started programming, so go easy on me ;)
In my program I make a board consisting of several buttons (btn[i, j]), which I create by using two for loops. These buttons are given a coordinate pair/index [i, j], then I pass this to a 2d array called valueBtn and I give that coordinate pair a value on the corresponding index.
public void board(object obj, EventArgs ea)
{
int n = 6;
Button[,] btn = new Button[n, n];
for (int i = 0; i < n; i++)
{
for (int j = 0; j < n; j++)
{
int p = 60 * i + 100;
int q = 60 * j + 100;
btn[i, j] = new Button();
btn[i, j].Location = new Point(p, q);
btn[i, j].Size = new Size(60, 60);
int[,] valueBtn = new int[n, n];
valueBtn[i, j] = 0;
this.Controls.Add(btn[i, j]);
}
}
btn[i, j].Click += btnPress;
}
Next I have a new method btnPress which is linked to the EventHandler btn[i, j].Click. The intention is that in this method I find out which button has been pressed, and which coordinates/index belongs to this so that I can find the corresponding value in the 2d array valueBtn and eventually draw this value in a new function drawValue.
public void btnPress(object sender, EventArgs ea)
{
Button pressedBtn = sender as Button;
// Here I want to know which button is pressed and the index [i,j] of the button
// so that I can find the value that belongs to the button in the 2d valueBtn array
.
.
.
this.Paint += drawValue;
}
I've tried a lot with references to the EventHandler, but I just can't figure it out.
Thank you very much in advance for your time and help!

You can set the Text property of each button like btn[i, j].Text = some i j combination. and then get it in btnPress method like this string s = (sender as Button).Text;. You can also use Tag property, so basically concept is same.

Related

Adding value from dynamically created textboxes into array (windows forms)

im making a project for university, for which i use windows forms. i have to create a program, where you can generate an several amount of textboxes and calculate all values. the calcutation is about the sum and average of every value combined. therefore i have two buttons, one to create the textboxes and another one to do the calculation (doTheMath_Click).
heres my code so far:
button for the calculation:
private void doTheMath_Click(object sender, EventArgs e)
{
int radius = int.Parse(numberofnumbers.Text)
int sum = 0;
for (int i = 0; i < zahlen.Length; i++)
{
sum += numbers[i];
}
double average = (double)sum / (double)radius;
total.Text = sum.ToString();
averagee.Text = average.ToString();;
}
int newtextboxn = 8;
int alingment = 200;
public TextBox addnewtextbox()
{
TextBox textbox = new TextBox();
this.Controls.Add(textbox);
if (newtextboxn % 18 == 0)
{
alingment += 200;
newtextboxn = 8;
textbox.Top = newtextboxn * 27;
textbox.Left = alingment;
}
else
{
textbox.Top = newtextboxn * 27;
textbox.Left = alingment;
}
newtextboxn = newtextboxn + 1;
return textbox;
}
button to print the textbox:
public void printTextbox(int radius)
{
for (int i = 0; i < radius; i++)
{
addnewtextbox();
}
}
private void printTheBox_Click(object sender, EventArgs e)
{
int radius = int.Parse(numberofnumbers.Text);
printTextboxandLabels(radius);
}
I had the idea to save the values of the textboxes in an array, but i dont know if it would work, because the array length should also be dynamically and i also dont know, how to initialize the array in the end. My other idea was to save the values in a list, but theres the same problem about the initialization.
i hope, that my problem is understandable and that you can help me.
i already surfed around stackoverflow, but i didnt found an idea to solve my problem.
thx
Just create a List where you store the created set of textboxes. Then you can use the code to loop over this list and retrieve the content of each textbox.
List<TextBox> textboxslist = new List<TextBox>();
and inside addnewtextbox() method fill textboxlist using The Add method.
textboxlist.Add(textbox);
then inside loop code in doTheMath_Click button you can access the values of each textbox by using Text Property.
for (int i = 0; i < textboxlist.Count; i++) {
int textboxvalue = int.Parse(textboxlist[i].Text);
sum += textboxvalue;
}

In C# how does one access the elements of an array of control labels created at runtime?

Over the years I've done a significant amount of programming in various forms of BASIC, including Visual Basic. When it comes to C# I'm quite confused. Below is the form load code for a mastermind program I am creating in C#. Everything works, until I try to create my marking routine.
public void Form1_Load(object sender, EventArgs e)
{
//int columns = 14;
Label[,] board = new Label[5,14];
for (int i = 0; i < 5; i++)
{
for (int j = 0; j < 14; j++)
{
board[i,j] = new Label();
board[i,j].AutoSize = false;
board[i,j].Size = Dummy.Size;
board[i,j].BorderStyle = BorderStyle.Fixed3D;
board[i,j].BackColor = Color.Beige;
board[i,j].Location = new Point(i * Dummy.Width+2, j * Dummy.Height+2);
board[i,j].Name = "board" + i.ToString() + "," + j.ToString();
board[i,j].Width = Dummy.Width - 4;
board[i,j].Height = Dummy.Height - 4;
board[i,j].TabIndex = 0;
//board[i][j].Text = i.ToString() +" "+ j.ToString();
panel2.Controls.Add(board[i,j]);
board[i,j].Click += new EventHandler(Label1_Click);
}
P2.Click += new EventHandler(P1_Click);
P3.Click += new EventHandler(P1_Click);
P4.Click += new EventHandler(P1_Click);
P5.Click += new EventHandler(P1_Click);
P6.Click += new EventHandler(P1_Click);
P7.Click += new EventHandler(P1_Click);
P8.Click += new EventHandler(P1_Click);
}
int marker = 14;
int each = 5;
Label[,] mark = new Label[each,marker];
// Instantiating all the buttons in the array
for (int i = 0; i < each; i++)
{
for (int j = 0; j < marker; j++)
{
mark[i, j] = new Label();
mark[i, j].AutoSize=false;
mark[i, j].Size = Minnie.Size;
mark[i, j].BorderStyle = Minnie.BorderStyle;
mark[i, j].BackColor = Color.Blue;
mark[i, j].Left = i * (Minnie.Width+2)+3;
mark[i, j].Top = j * Dummy.Height+10;
panel3.Controls.Add(mark[i, j]);
}
}
}
This creates the playing 'holes' for guesses, and smaller marking 'holes' in panels 2 and 3, respectively. The playing part works fine as I have a selection panel that allows the user to choose colors and then 'place' the colors by clicking the board holes array. The various colours are matched by numbers which I append to the .Tag of board elements when they are clicked. The diffculty comes when I try to read the .Tags to assess the guesses for marking. Here is the code that is not working:
public void button1_Click(object sender, EventArgs e)
{
int r;
for (r=0;r<5;r++) {
textBox1.Text = textBox1.Text + board[0,r].Tag;
//board[0, r].BackColor = Color.Azure;
}
}
The board[0, r].BackColor = Color.Azure; was an attempt to isolate where the error derives. It generated the same error, so it seems that the button routine knows that 'board' exists but doesn't acknowledge or is unable to access the subscripted elements. The error generated is:
▶ $exception {"Object reference not set to an instance of an object."} System.NullReferenceException
What do I need to do in order to overcome this difficulty?
Thanks in advance,
Cam
Each variable has a scope: the section of code where that variable is valid. If you define it in a method, then the variable can only be used within that method.
So in this case, if you want to use that variable in multiple methods, you need to declare in a scope that encompasses those methods. In this case, that is your Form1 class - so just inside the declaration of the class, but outside any method.
But you also need to remove the declaration inside Form1_Load too, otherwise you'll end up with two variables with the same name and different scopes. They may have the same name, but they will refer to two different places in memory and not hold the same data. When you use board inside Form1_Load you will refer to the one declared inside that method, and it will be destroyed as soon as the method finishes.

Can we use parameter in mouse click event c# [duplicate]

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.

how to place my button?

I have a problem with my C# WinForm project.
In my project I have a function to draw a square, and I have a function that makes buttons at run time. What I want to do is that the button will place on the square.
I try to use 2 arrays; one gets the x location of the square, and the other gets the y location.
The button is placed at the x and y location one by one in columns but its place them diagonal.
int[] locationx = new int[100];
int[] locationy = new int[100];
int monex = 0;
int money = 0;
private void DrawAllSquares()//z,k its many square its going to draw
{
int tempy = y;
for (int i = 0; i < z; i++)
{
DrawingSquares(x, y);
for (int j = 0; j < k - 1; j++)
{
locationy[money] = tempy;
money++;
tempy += 60;
DrawingSquares(x, tempy);
}
x += 120;
locationx[monex] = x;
monex++;
tempy = y;
}
}
private void button2_Click(object sender, EventArgs e)
{
Button myText = new Button();
myText.Tag = counter;
//changeplace();
myText.Location = new Point(locationx[monex2], locationy[money2]);
monex2++;
money2++;
buttonList.AddLast(myText);
myText.Text = Convert.ToString(textBox3.Text);
this.Controls.Add(myText);
buttons[counter] = myText;
myText.BringToFront();
counter++;
}
You need do add created button to Form Controls collection.
private void button2_Click(object sender, EventArgs e)
{
Button myText = new Button();
myText.Tag = counter;
myText.Location = new Point(locationx[monex2], locationy[money2]);
Controls.Add(myText); // Assuming that handler 'button2_Click' is in your Form class.
// rest of your code
}
EDIT:
Button myText = new Button();
myText.Click += button2_Click;

EventHandlers and the sender

So in my program i created a struct with a button and a number value... like this
struct box
{
public int numberValue;
public Button button;
}
I then made a 2D array of this struct
box[,] boxes = new box[20, 20];
Now what i did was make 400 buttons and assigned them to each index of the array... like this
private void createBoxes()
{
int positionX;
int positionY;
for (int i = 0; i < 20; i++)
{
for (int j = 0; j < 20; j++)
{
positionX = 20 + (25 * i);
positionY = 20 + (25 * j);
boxes[i, j].button = new System.Windows.Forms.Button();
boxes[i, j].button.Location = new System.Drawing.Point(positionX,positionY);
boxes[i, j].button.Size = new System.Drawing.Size(25, 25);
this.Controls.Add(boxes[i, j].button);
boxes[i, j].button.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
boxes[i, j].button.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
boxes[i, j].button.Visible = true;
boxes[i, j].button.Name = "button";
boxes[i, j].button.Click += new EventHandler(buttonClick);
}
}
}
Now when i make the event handler i want to send "boxes[i,j]" not just "boxes[i,j].button" is there anyway to do this?
Short of defining your own anonymous event handler, there's an easy way to do what you want:
boxes[i, j].button.Tag = boxes[i, j];
Then later:
private void buttonClick(object sender, EventArgs e)
{
var box = ((Button)sender).Tag as box;
}
This can be solved via an anonymous event handler.
var box = boxes[i, j]; // You must use a new variable within this scope
box.button.Click += (obj, args) => buttonClick(box, args);
This is the quickest solution with the least code. Just be aware that anonymous event handlers are notorious for hidden gotchas, and the need to assign a new box variable is an example. The following code will run, but no matter which button you press, the last-assigned values of i and j would be used within the handler.
boxes[i,j].button.Click += (obj, args) => buttonClick(boxes[i,j], args);
No, this is not possible. The individual button control is the one that raises the event, thus it is the object referenced by the sender parameter. The array that contains the button control is irrelevant.
This behavior is by-design. If you wanted to change a property of the button in response to the user clicking on it, it would be impossible to do unless you knew which individual button was clicked. Having only a reference to the array that contains all of the buttons would not provide sufficient information about the individual button that was clicked.

Categories