How can I access to my Grid table from my private method - c#

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.

Related

Why dont buttons show up in the grid when I create them using a for loop in C# WPF?

Trying to make a board for a Connect 4 game using buttons however after creating a method to create the actual board itself by creating buttons for each individual cell in the grid,nothing shows up.
public partial class MainWindow : Window
{
private readonly int[,] _board;
private readonly int _height;
private readonly bool _isComp;
private readonly Brush _p1Color;
private readonly string _p1Name;
private readonly Ellipse _p1Sym;
private readonly int _width;
private readonly int _win;
private Ellipse mycircle;
private bool _isFalling;
private bool turnPlayer1;
private int _turns;
private string _winner;
public string Mode;
public int[,] BoardArray = new int[5, 6];
public MainWindow()
{
}
public MainWindow (int row, int column , int win, Ellipse newP1, Ellipse newP2, Brush p1Color, Brush p2Color,
string p1Name, string p2Name, bool isComp, int time, string mode, Brush back, Uri music)
{
InitializeComponent();
turnPlayer1 = true;
for (int loopColumn = 0; loopColumn <= 6; loopColumn++)
{
for (int loopRow = 0; loopRow <= 5; loopColumn++)
{
BoardArray[loopRow, loopColumn] = 0;
}
}
row = 6;
column = 7;
CreateBoard(column, row);
mycircle = newP1;
_p1Color = p1Color;
_p1Name = p1Name;
_win = win;
_winner = "";
_isComp = isComp;
Mode = mode;
}
private void buttonClicked(Button btn)
{
var rowDef = Grid.GetRow(btn);
var columnDef = Grid.GetColumn(btn);
var col = columnDef;
DropCounter(col);
}
private int EmptyRow(int column)
{
for(int row = 6-1;row >=0;row-- )
{
var arrayRow = row; ;
var arrayCol = column;
if(BoardArray[row,column]== 0)
{
return row;
}
}
return -1;
}
private void DropCounter(int column)
{
var freeRow = EmptyRow(column);
if (freeRow == -1) return;
mycircle = new Ellipse();
mycircle.Stroke = System.Windows.Media.Brushes.Black;
mycircle.Fill = System.Windows.Media.Brushes.DarkBlue;
mycircle.Height = 100;
mycircle.Width = 100;
Grid.SetColumn(mycircle, 1);
Grid.SetRow(mycircle, 1);
myGrid.Children.Insert(0,mycircle);
}
private void Btn_Click(object sender, RoutedEventArgs e)
{
if (sender is Button btn && EmptyRow(Grid.GetColumn(btn)) != -1) buttonClicked(btn);
}
private void CreateBoard(int column,int rows)
{
for (var row = 0; row < rows; row++)
{
for (var col = 0; col < column; column++)
{
Button button = new Button();
{
var brush = new ImageBrush();
brush.ImageSource = new BitmapImage(new Uri("gridsingle.png.bmp", UriKind.Relative));
button.Background = brush;
Name = "btn_" + row + "_" + column;
};
button.Click += Btn_Click;
Grid.SetRow(button, row);
Grid.SetColumn(button, column);
myGrid.Children.Add(button);
}
}
}
}
}
Apologies for the messy code,this is a HW assignment for highschool and programming isnt my favourite part of the course
Not really sure whats the main cause as I am implementing the same code as my friend yet his buttons all load on his window.
I'll be honest, there are actually a whole lot of things wrong with this. Normally I'd recommend throwing it out and starting again, but I'm guessing time is a factor, so I'll do my best to help.
First of all, this doesn't look right:
public MainWindow()
{
}
public MainWindow(int row, int column, int win, Ellipse newP1, Ellipse newP2, Brush p1Color, Brush p2Color, string p1Name, string p2Name, bool isComp, int time, string mode, Brush back, Uri music)
{
Ordinarily, the first constructor is the one that gets called, and since your implementation is empty, it explains why you aren't seeing anything. Looking at your code, the parameters being passed into your second constructor aren't actually being used, so get rid of both constructors and just keep the logic needed to initialize your board:
public MainWindow()
{
InitializeComponent();
turnPlayer1 = true;
for (int loopColumn = 0; loopColumn <= 6; loopColumn++)
{
for (int loopRow = 0; loopRow <= 5; loopRow++)
{
BoardArray[loopRow, loopColumn] = 0;
}
}
var row = 6;
var column = 7;
CreateBoard(column, row);
_winner = "";
}
You'll notice there was a bug in your original code which I've fixed:
for (int loopColumn = 0; loopColumn <= 6; loopColumn++)
{
for (int loopRow = 0; loopRow <= 5; loopColumn++)
That second loop should be incrementing loopRow, not loopColumn. (As a side note, you've hard-coded these loops to 6 columns, and 5 rows, they should instead be using the values in the column and row variables).
Next, there's a bug in your CreateBoard function:
private void CreateBoard(int column, int rows)
{
for (var row = 0; row < rows; row++)
{
for (var col = 0; col < column; column++)
The column variable is storing the total number of columns, so you should be doing col++, not column++. Similarly, when you set the Grid column for the button, you should be setting it to col, not column:
button.Click += Btn_Click;
Grid.SetRow(button, row);
Grid.SetColumn(button, column); // <---- this is wrong
myGrid.Children.Add(button);
The code in your DropCounter function also has problems:
Grid.SetColumn(mycircle, 1);
Grid.SetRow(mycircle, 1);
myGrid.Children.Insert(0, mycircle);
Notice you're always setting the column and row to 1, you should be setting them to column and freeRow.
Last of all, you're never updating BoardArray to make note of the fact that tokens are being dropped, so you'll just keep dropping them on the bottom row. You need to update it at the end of your DropCounter function so that your EmptyRow function works correctly:
BoardArray[freeRow, column] = 1;

How to create an array with pictureboxes in Windows Forms (C#)

I am fairly new to C# and I can't figure out how to create an array with visible picture boxes inside the cs file. In this example I want to create 200 picture boxes 10x20 to create an grid for a tetris game. This is my code, I can't get any of the pictures to show but the code runs just fine.
Image[] blockImage = {
TetrisSlutprojekt.Properties.Resources.TileEmpty,
TetrisSlutprojekt.Properties.Resources.TileCyan,
TetrisSlutprojekt.Properties.Resources.TileBlue,
TetrisSlutprojekt.Properties.Resources.TileRed,
TetrisSlutprojekt.Properties.Resources.TileGreen,
TetrisSlutprojekt.Properties.Resources.TileOrange,
TetrisSlutprojekt.Properties.Resources.TilePurple,
TetrisSlutprojekt.Properties.Resources.TileYellow
};
PictureBox[] blockBoxes = new PictureBox[200];
private void CreateBoxes()
{
for (int i = 0; i < blockBoxes.Length; i++)
{
blockBoxes[i] = new System.Windows.Forms.PictureBox();
blockBoxes[i].Name = "pbBox" + i;
blockBoxes[i].Size = new Size(30, 30);
blockBoxes[i].Visible = true;
}
}
private void PlaceBoxes()
{
for (int y = 0; y < rows; y++)
{
for (int x = 0; x < columns; x++)
{
blockBoxes[y].Top = y * blockWidth;
blockBoxes[x].Left = x * blockWidth;
}
}
}
private void FillBoxes()
{
for (int i = 0; i < blockBoxes.Length; i++)
{
blockBoxes[i].Image = blockImage[4];
}
}
Add them to the Form:
private void CreateBoxes()
{
for (int i = 0; i < blockBoxes.Length; i++)
{
blockBoxes[i] = new System.Windows.Forms.PictureBox();
blockBoxes[i].Name = "pbBox" + i;
blockBoxes[i].Size = new Size(30, 30);
blockBoxes[i].Visible = true;
this.Controls.Add(blockBoxes[i]); // <--- HERE
}
}

Unit test a dynamically populating user control in WinForms

I have a WinForms project with MVP pattern (passive view) implemented.
I think that I have a problem with the pattern when it comes to a user control, which I figured out during unit testing
I have a user control that I put on my form as a result of an event fired in my view. That user control adds a certain amount of labels, textboxes, etc. to itsself based on a number it gets from the view. Finally, it tells the view to add the user control to the view.
I want to unit test the logic in this class, since that is what I think is most important to test. I just do not know how to do this, since there is both logic and form controls in this class. I am currently using Moq for creating my unit tests.
I would normally create a Mock object to represent the view and then test the implementation of the methods in the object to be tested in isolation. However, since I create controls in this class, I don't think I can test this like this (without including the .Forms library that is).
I hope someone knows a solution.
EDIT: I have been trying to separate my logic from the control manipulation, but I am struggling with a function from a different user control I have posted below the original user control code. Since I loop through a list of controls, I dont know how to separate this into just logic and just control handling.
User control code
public partial class DetailScreenUserControl : UserControl
{
// Private members.
private readonly IDetailScreenView _view;
private List<ComboBox> maturityInput = new List<ComboBox>();
private List<ComboBox> complianceInput = new List<ComboBox>();
// Public members.
public List<string> MaturityInput
{
get
{
var list = new List<string>();
for (int i = 0; i < maturityInput.Count; i++)
{
list.Add(maturityInput[i].Text);
}
return list;
}
set
{
for (int i = 0; i < maturityInput.Count; i++)
{
maturityInput[i].DataSource = new List<string>(value);
}
}
}
public List<string> ComplianceInput
{
get
{
var list = new List<string>();
for (int i = 0; i < complianceInput.Count; i++)
{
list.Add(complianceInput[i].Text);
}
return list;
}
set
{
for (int i = 0; i < complianceInput.Count; i++)
{
complianceInput[i].DataSource = new List<string>(value);
}
}
}
// Initialize user control with IDetailScreenView. Subscribe to necessary events.
public DetailScreenUserControl(IDetailScreenView view)
{
InitializeComponent();
_view = view;
_view.InitializingUserControl += InitializeUserControl;
}
// Initializes the user control for the detail screen.
public void InitializeUserControl(object sender, EventArgs e)
{
List<string> qStandards = _view.SelectedQuestionStandards;
Controls.Clear();
maturityInput.Clear();
complianceInput.Clear();
int inputSeparation = Height / 2;
int spacing = Width / 20;
Size = new Size(_view.RightUserControlBoundary - Location.X, Size.Height);
for (int i = 0; i < qStandards.Count; i++)
{
Panel inputPanel = new Panel();
inputPanel.BackColor = Color.AliceBlue;
inputPanel.Location = new Point(0, i * inputSeparation);
inputPanel.Size = new Size(Width - spacing, inputSeparation);
Controls.Add(inputPanel);
Label qs_label = new Label();
qs_label.AutoSize = true;
qs_label.Location = new Point(0, 0);
qs_label.Font = new Font("Arial", 12F, FontStyle.Bold);
qs_label.AutoSize = true;
qs_label.Text = qStandards[i].ToString();
inputPanel.Controls.Add(qs_label);
Label m_label = new Label();
m_label.AutoSize = true;
m_label.Location = new Point(0, qs_label.Bounds.Bottom + qs_label.Height / 2);
m_label.Font = new Font("Arial", 12F, FontStyle.Regular);
m_label.Text = "Maturity standard";
inputPanel.Controls.Add(m_label);
Label c_label = new Label();
c_label.AutoSize = true;
c_label.Location = new Point(0, m_label.Bounds.Bottom + qs_label.Height / 2);
c_label.Font = new Font("Arial", 12F, FontStyle.Regular);
c_label.Text = "Compliance standard";
inputPanel.Controls.Add(c_label);
ComboBox m_input = new ComboBox();
m_input.AutoSize = true;
m_input.Location = new Point(c_label.Bounds.Right + 2 * spacing, m_label.Bounds.Top);
m_input.Font = new Font("Arial", 10F, FontStyle.Regular);
m_input.DropDownStyle = ComboBoxStyle.DropDownList;
m_input.Size = new Size(inputPanel.Size.Width - m_input.Bounds.Left, spacing);
maturityInput.Add(m_input);
inputPanel.Controls.Add(m_input);
ComboBox c_input = new ComboBox();
c_input.AutoSize = true;
c_input.Location = new Point(c_label.Bounds.Right + 2 * spacing, c_label.Bounds.Top);
c_input.Font = new Font("Arial", 10F, FontStyle.Regular);
c_input.DropDownStyle = ComboBoxStyle.DropDownList;
c_input.Size = new Size(inputPanel.Size.Width - c_input.Bounds.Left, spacing);
complianceInput.Add(c_input);
inputPanel.Controls.Add(c_input);
}
if(qStandards.Count != 0)
{
saveAssessmentButton.BackColor = System.Drawing.SystemColors.ButtonHighlight;
Controls.Add(saveAssessmentButton);
saveAssessmentButton.Location = new Point(this.Size.Width - saveAssessmentButton.Width - spacing, qStandards.Count * inputSeparation);
}
_view.AddUserControl();
}
// Tells the view to save the assessment.
private void saveAssessmentButton_Click(object sender, EventArgs e)
{
_view.SaveAssessmentButtonClicked();
}
}
Other user control function('answers' is the list of controls)
public void SaveResults()
{
results = new List<string>();
int questionNr = 0;
for (int p = 0; p < questions.Count; p++)
{
for (int i = 0; i < questions[p].Count; i++)
{
bool unanswered = true;
results.Add(questions[p][i]);
for (int j = 1; j <= maturityAnswers[p].Count; j++)
{
var radioButton = (RadioButton)answers[questionNr][j];
if (radioButton.Checked)
{
results.Add(answers[questionNr][j].Text);
unanswered = false;
}
}
if (unanswered == true)
{
results.Add("");
}
unanswered = true;
for (int j = maturityAnswers[p].Count + 1; j <= (maturityAnswers[p].Count + complianceAnswers[p].Count); j++)
{
var radioButton = (RadioButton)answers[questionNr][j];
if (radioButton.Checked)
{
results.Add(answers[questionNr][j].Text);
unanswered = false;
}
}
if (unanswered == true)
{
results.Add("");
}
results.Add(answers[questionNr][0].Text.Replace("'", "''"));
questionNr++;
}
}
I want to unit test the logic in this class, since that is what I
think is most important to test. I just do not know how to do this,
since there is both logic and form controls in this class
So separate them to different classes and test the class which contains only logic

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.

C# How to define event for dynamically created control?

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

Categories