WPF Get Stackpanel children neighbors - c#

I have a stackpanel that I have dynamically added buttons to, based on a 2D array defined elsewhere. So essentially it builds a grid of buttons, but added as children of the stackpanel. What I need to be able to do, is specify a child button based on column and row number. Here's the Stackpanel.
<StackPanel Name="myArea" HorizontalAlignment="Center" VerticalAlignment="Center"/>
And here's some of the code in question.
Grid values = new Grid();
values.Width = 320;
values.Height = 240;
values.HorizontalAlignment = HorizontalAlignment.Center;
values.VerticalAlignment = VerticalAlignment.Center;
int x = valueBoard.GetLength(0);
int y = valueBoard.GetLength(1);
for (int i = 0; i < x; i++)
{
ColumnDefinition col = new ColumnDefinition();
values.ColumnDefinitions.Add(col);
}
for (int j = 0; j < y; j++)
{
RowDefinition row = new RowDefinition();
values.RowDefinitions.Add(row);
}
for (int i = 0; i < x; i++) for (int j = 0; j < y; j++)
{
Button button = new Button();
button.Content = "";
button.Click += ButtonClick;
button.MouseRightButtonUp += RightClick;
Grid.SetColumn(button, i);
Grid.SetRow(button, j);
values.Children.Add(button);
}
myArea.Children.Add(values);
So now, on click of a button, I want to hide all adjacent buttons in the grid. Here's my click event:
private void ButtonClick(object sender, RoutedEventArgs e)
{
int col = Grid.GetColumn((Button)sender);
int row = Grid.GetRow((Button)sender);
Button source = e.Source as Button;
source.Visibility = Visibility.Hidden;
}
How would I, in ButtonClick, hide the neighbor buttons with the col and row values? Is there some sort of getter or setter than I can feed those values into and edit the neighbor's Visibility property?

try the following:
private void ButtonClick(object sender, RoutedEventArgs e)
{
int col = Grid.GetColumn((Button)sender);
int row = Grid.GetRow((Button)sender);
Button source = e.Source as Button;
source.Visibility = Visibility.Hidden;
Grid pGrid = source.Parent as Grid;
if (pGrid == null) throw new Exception("Can't find parent grid.");
for (int i = 0; i < pGrid.Children.Count; i++) {
Button childButton = pGrid.Children[i] as Button;
if(childButton == null) continue;
int childCol = Grid.GetColumn(childButton);
int childRow= Grid.GetRow(childButton);
if(Math.Abs(childCol - col) < 2 && Math.Abs(childRow - row) < 2) childButton.Visibility = Visibility.Hidden;
}
}
this iterates through your children and if it is type of Button it will check, if the row and column is next to your Source and will hide it.

Related

c# uwp drag and drop - cant make a swap

so i i hade 10x10 grid with pics and i want to swap by drag and drop and i actually cant get
the imgages the targeted and the selected in order to make the spaw
i made all from view model code
in the evens the sender is a grid and the e is DragEventArgs
public MainViewModel()
{
GameGrid = new Grid { AllowDrop = true };
GameGrid.DragOver += GameGrid_DragOver;
GameGrid.Drop += GameGrid_Drop;
for (int row = 0; row < 10; row++)
{
GameGrid.RowDefinitions.Add(new RowDefinition());
for (int col = 0; col < 10; col++)
{
if (row == 0)
GameGrid.ColumnDefinitions.Add(new ColumnDefinition());
var image = new Image { Source = logic.GetImage(), CanDrag = true, AllowDrop = true };
Grid.SetRow(image, row);
Grid.SetColumn(image, col);
GameGrid.Children.Add(image);
}
}
}
private void GameGrid_DragOver(object sender, Windows.UI.Xaml.DragEventArgs e)
{
e.AcceptedOperation = DataPackageOperation.Move;
}
private async void GameGrid_Drop(object sender, Windows.UI.Xaml.DragEventArgs e)
{
if (logic.IsValidSwap(selected, selected))
{
}
}
// but i cant get the imeges to send the func is validswap
Instead of assigning in the event to the grid:
GameGrid.DragOver += GameGrid_DragOver;
GameGrid.Drop += GameGrid_Drop;
It should be assigned to each image inside the for loop:
image.Drop += GameGrid_Drop;
image.DragOver += GameGrid_DragOver;
And than the sender will be the image—you can know the col and row and make switches.

How can I create a Grid in UWP that changes at runtime along with a 2D array?

I'm creating a boardgame app with UWP and C#. Currently my board is defined as a 2D array that grows as the tiles are placed. I'd like to be able to have a grid that grew with the array. I also wanted the empty spaces in the grid to be defined as buttons to be able to place the tile in the grid with a click.
I tried using this method in the backend code based on an answer I saw on this link but I don't think I'm doing things the right way.
public Grid GridGenerator(int rows, int cols, int[,] map)
{
Grid grid = new Grid();
grid.Margin = new Thickness(50, 50, 50, 50);
grid.Background = new SolidColorBrush(Windows.UI.Colors.Brown);
grid.HorizontalAlignment = HorizontalAlignment.Center;
grid.VerticalAlignment = VerticalAlignment.Center;
for (int i = 0; i < rows; i++)
{
RowDefinition Row = new RowDefinition();
Row.Height = new GridLength(0, GridUnitType.Auto);
grid.RowDefinitions.Add(Row);
for (int j = 0; j < cols; j++)
{
ColumnDefinition column = new ColumnDefinition();
column.Width = new GridLength(0, GridUnitType.Auto);
grid.ColumnDefinitions.Add(column);
if (map[i, j] == 0)
{
Button button = new Button();
button.MinHeight = 30;
button.MinWidth = 30;
button.Background = new SolidColorBrush(Windows.UI.Colors.AliceBlue);
button.Name = i.ToString() + j.ToString();
grid.Children.Add(button);
Grid.SetColumn(button, j);
}
else
{
TextBlock text = new TextBlock();
text.Text = map[i, j].ToString();
text.HorizontalTextAlignment = (TextAlignment)HorizontalAlignment.Center;
text.HorizontalAlignment = HorizontalAlignment.Center;
text.VerticalAlignment = VerticalAlignment.Center;
grid.Children.Add(text);
Grid.SetColumn(text, j);
}
}
}
It seems you are adding too many ColumnDefinitions through the nested loop. Try writing each step separately so that you can grasp what to do.
public Grid GridGenerator(int rows, int cols, int[,] map)
{
Grid grid = new Grid();
:
// 1.Prepare RowDefinitions
for (int i = 0; i < rows; i++)
{
RowDefinition Row = new RowDefinition();
Row.Height = new GridLength(0, GridUnitType.Auto);
grid.RowDefinitions.Add(Row);
}
// 2.Prepare ColumnDefinitions
for (int j = 0; j < cols; j++)
{
ColumnDefinition column = new ColumnDefinition();
column.Width = new GridLength(0, GridUnitType.Auto);
grid.ColumnDefinitions.Add(column);
}
// 3.Add each item and set row and column.
for (int i = 0; i < rows; i++)
{
for (int j = 0; j < cols; j++)
{
if (map[i, j] == 0)
{
Button button = new Button();
:
grid.Children.Add(button);
Grid.SetColumn(button, j);
Grid.SetRow(button, i); // Set row too!
}
:
}
}
return grid;
}
Appendix
How to display the grid generated in code behind:To display it, you need to put it in XAML tree. For example, if you'd like to show it in another Grid (named "LayoutRoot") in XAML page,
<Grid x:Name="LayoutRoot"></Grid>
add it to LayoutRoot.Children in the code behind.
Grid board_grid = GridGenerator(5, 5, map);
LayoutRoot.Children.Add(board_grid);

How can I access to my Grid table from my private method

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.

WinForms dynamic matrix new form with button

So I managed to create a dynamic array of text boxes in a new form with a button beneath, but the button is overlapping some of the text boxes as seen in the screenshot:
http://prntscr.com/l7ln4q
I'd like to add a margin and padding to the array so the button is underneath the array
This is the code that generates the array:
int LinhaText = frmDim.linhas;
int ColunText = frmDim.colunas;
const int TEXTBOX_WIDTH = 30;
const int TEXTBOX_HEIGHT = 30;
const int SPACING = 0;
List<List<TextBox>> textboxes = new List<List<TextBox>>();
private void Form2_Load(object sender, EventArgs e)
{
for (int row = 0; row < LinhaText; row++)
{
List<TextBox> newRow = new List<TextBox>();
textboxes.Add(newRow);
for (int col = 0; col < ColunText; col++)
{
TextBox newbox = new TextBox();
newbox.Width = TEXTBOX_WIDTH;
newbox.Height = TEXTBOX_HEIGHT;
newbox.Top = (row * (TEXTBOX_HEIGHT + SPACING)) + SPACING;
newbox.Left = (col * (TEXTBOX_WIDTH + SPACING)) + SPACING;
newRow.Add(newbox);
this.Controls.Add(newbox);
}
}
}
The generation of the array works just fine.
Try this if you just want a simple solution:
private void Form1_Load(object sender, EventArgs e)
{
Panel p = new Panel(); // added code
for (int row = 0; row < LinhaText; row++)
{
List<TextBox> newRow = new List<TextBox>();
textboxes.Add(newRow);
for (int col = 0; col < ColunText; col++)
{
TextBox newbox = new TextBox();
newbox.Width = TEXTBOX_WIDTH;
newbox.Height = TEXTBOX_HEIGHT;
newbox.Top = (row * (TEXTBOX_HEIGHT + SPACING)) + SPACING;
newbox.Left = (col * (TEXTBOX_WIDTH + SPACING)) + SPACING;
newRow.Add(newbox);
p.Controls.Add(newbox); // modified code (added textboxes to panel rather than form)
}
}
// added code
p.Dock = DockStyle.Fill;
this.Controls.Add(p);
this.Controls.SetChildIndex(p, 0);
Button b1 = new Button();
b1.Text = "hi";
b1.Dock = DockStyle.Bottom;
this.Controls.Add(b1);
this.Controls.SetChildIndex(b1, 1);
}

c# Dynamic panel on mouse

I am making a N*M size SUDOKU game. Every number are on a button.
When the program start all button is empty and I would like if I click to a button it is make a little panel on it with buttons for each number to choose one.
private void adatB_Click(object sender, EventArgs e)
{
Button button = sender as Button;
int[] hely = button.Tag.ToString().Split(new string[] { "," }, StringSplitOptions.RemoveEmptyEntries).Select(Int32.Parse).ToArray();
Panel szamok = new Panel
{
Location = MousePosition,
Size = new Size(100, 100)
};
Controls.Add(szamok);
TableLayoutPanel minitabla = new TableLayoutPanel
{
Dock = DockStyle.Fill,
ColumnCount = szorzat,
RowCount = szorzat,
};
for (int i = 0; i < szorzat; i++)
{
minitabla.RowStyles.Add(new RowStyle(SizeType.Percent, 100F));
minitabla.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 100F));
}
szamok.Controls.Add(minitabla);
Button[,] szamokB = new Button[meret[0], meret[1]];
int d = 1;
for (int i = 0; i < meret[0]; i++)
{
for (int j = 0; j < meret[1]; j++)
{
szamokB[i, j] = new Button();
szamokB[i, j].Tag= hely[0]+","+hely[1];
szamokB[i, j].Text = d.ToString();
szamokB[i, j].Dock = DockStyle.Fill;
szamokB[i, j].Click += szamokB_Click;
minitabla.Controls.Add(szamokB[i, j], i, j);
d++;
}
}
}
private void szamokB_Click(object sender, EventArgs e)
{
Button button = sender as Button;
int[] hely = button.Tag.ToString().Split(new string[] { "," }, StringSplitOptions.RemoveEmptyEntries).Select(Int32.Parse).ToArray();
adatB[hely[0], hely[1]].Text = button.Text;
}
The problem with it when I click a button the pane isn't created.
meret[0] variable is the N, meret[1] is M, adatB is the arry of buttons with the positons in tag.
And If I choosed the number how can I close that panel?
First of all, you should calculate the mouseposition correctly.
From MSDN:
Gets the position of the mouse cursor in screen coordinates.
You should use something like this:
Location = new Point(MousePosition.X - this.Location.X, MousePosition.Y - this.Location.Y)
You will probably need this, to bring your panel to the front:
Controls.Add(szamok);
szamok.BringToFront();
To close the panel you can store the chooser panel and you can remove it from the controls later, use something like this:
public partial class Form1 : Form
{
private Panel myPanel = null;
private void adatB_Click(object sender, EventArgs e)
{
...
Panel szamok = new Panel
{
Location = new Point(MousePosition.X - this.Location.X, MousePosition.Y - this.Location.Y),
Size = new Size(100, 100)
};
if (this.myPanel != null)
{
this.Controls.Remove(this.myPanel);
}
this.myPanel = szamok;
Controls.Add(szamok);
szamok.BringToFront();
...
}
private void szamokB_Click(object sender, EventArgs e)
{
if (this.myPanel != null)
{
this.Controls.Remove(this.myPanel);
this.myPanel = null;
}
...
}
}

Categories