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.
Related
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.
I started yesterday a new proyect in c# with WPF. My first time with it.
I'm trying to do the tictactoe game with graphical interface so i create the grid and i use bottons to change the state (it's not finish yet).
Here is the declaration of the class:
public partial class juego : Window
{
private juego tab;
public juego( int size)
{
InitializeComponent();
this.tab = CreateDynamicWPFGrid(size);
}
Here is the method that created the grid.
public juego CreateDynamicWPFGrid(int size)
{
Grid DynamicGrid = new Grid();
DynamicGrid.Name = "GridTablero";
DynamicGrid.Width = 400;
DynamicGrid.HorizontalAlignment = HorizontalAlignment.Left;
DynamicGrid.VerticalAlignment = VerticalAlignment.Top;
DynamicGrid.ShowGridLines = true;
DynamicGrid.Background = new SolidColorBrush(Colors.LightSteelBlue);
for (int i = 0; i < size; i++)
{
ColumnDefinition gridCol1 = new ColumnDefinition();
DynamicGrid.ColumnDefinitions.Add(gridCol1);
RowDefinition gridRow1 = new RowDefinition();
gridRow1.Height = new GridLength(45);
DynamicGrid.RowDefinitions.Add(gridRow1);
}
for (int fila = 0; fila < DynamicGrid.RowDefinitions.Count; fila++)
{
for (int columna = 0; columna < DynamicGrid.RowDefinitions.Count; columna++)
{
System.Windows.Controls.Button newBtn = new Button();
newBtn.Content = fila.ToString() + "_" + columna.ToString();
newBtn.Name = "Button" + fila.ToString() + "_" + columna.ToString();
newBtn.SetValue(Grid.ColumnProperty, columna);
newBtn.SetValue(Grid.RowProperty, fila);
newBtn.Click += new RoutedEventHandler(button_Click);
DynamicGrid.Children.Add(newBtn);
}
}
tablero.Content = DynamicGrid;
return tablero;
}
So the thing is that i want to iterate over the grid and then, count the buttons which content means if they are X, O or white.
I tried to use in my private method something like tab.Content but i really don't have any idea.
Anyways, i would like to know if this it is even possible.
After all, i come up with a solution by myselft.
So, i changed some lines in the class.
public partial class juego : Window
{
private ArrayList jugadores;
public juego(ArrayList jugadores, int size)
{
InitializeComponent();
tablero.Content = CreateDynamicWPFGrid(size);
}
Then i changed the return from the CreateDynamicWPFGrid:
return dynamicGrid;
And then, one method that i call when i click on buttons.
Grid boardValidar = tablero.Content as Grid;
Button[,] botones = new Button[boardValidar.ColumnDefinitions.Count, boardValidar.ColumnDefinitions.Count];
var buttons = boardValidar.Children.Cast<Button>();
for (int i = 0; i < boardValidar.ColumnDefinitions.Count; i++)
{
for (int j = 0; j < boardValidar.RowDefinitions.Count; j++)
{
botones[i, j] = buttons.Where(x => Grid.GetRow(x) == j && Grid.GetColumn(x) == i).FirstOrDefault();
}
}
So, i cast the grid and then, i do the same with all the buttons.
After this i use the linq to put in the array and that's all.
I know my code it's no the best but i got what i wanted.
I am trying to make a tic tac toe game where the user inputs the dimensions and then a board is created with buttons. When a button is clicked, it is disabled and the text inside changes to "X" or "O" accordingly. The user plays against a very basic "AI" which picks the buttons at random.I'm trying to check for empty (enabled) buttons on the board but I get the error:
System.NullReferenceException: 'Object reference not set to an instance of an object.'
heres the code:
public partial class Form1 : Form{
int num;
Button[,] buttonspinak;
private void button2_Click(object sender, EventArgs e)
{
int start = 180, end = 30;
num = Convert.ToInt32(textBox1.Text);
buttonspinak = new Button[num, num];
for (int i = 0; i < num; i++)
{
end += 80;
start = 180;
for (int j = 0; j < num; j++)
{
Button b = new Button();
b.Size = new Size(60, 60);
b.Location = new Point(start, end);
this.Controls.Add(b);
start += 80;
b.BackColor = Color.White;
buttonspinak[i, j] = b;
b.Click += new EventHandler(Computer2);
Computer(sender, e);
}
}
}
int countercomputer;
Random randcompu = new Random();
private void Computer(object sender, EventArgs e)
{
int randomi = 0;
int randomj = 0;
Button b = (Button)sender;
b.Enabled = false;
randomi = randcompu.Next(0, num);
randomj = randcompu.Next(0, num);
**while (buttonspinak[randomi, randomj].Text == "O" || buttonspinak[randomi, randomj].Text == "X")** // this is the line where i get the error
{
randomi = randcompu.Next(0, num);
randomj = randcompu.Next(0, num);
//buttonspinak[randomi, randomj].Text = "C";
}
buttonspinak[randomi, randomj].Text = "O";
b_Elegxos();
}
private void Computer2(object sender, EventArgs e)
{
countercomputer++;
Button b = (Button)sender;
b.Enabled = false;
if (countercomputer % 2 != 0)
{
b.Text = "X";
b.ForeColor = Color.DarkRed;
}
b_Elegxos();
}
}
You seem to call Computer() in each iteration of your nested for loop in the button2_Click handler.
This means that, after only initializing buttonspinak[0,0] with a new Button, Computer() gets called, which picks a random position in buttonspinak and tries to get that element's Text. But, most likely, that position in the array isn't initialized yet, so you're trying to call .Text on a null reference, resulting in your exception.
You should in stead call Computer() after the for loops in button2_Click, so you can be sure all positions in buttonspinak are initialized.
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
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;