Accessing grid elements programmatically - c#

Let's say I have:
<Grid Name="paramGrid">
<Grid.ColumnDefinitions>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
<TextBox Grid.Row="0" Grid.Column="0"/>
<TextBox Grid.Row="1" Grid.Column="0"/>
</Grid>
I am aware of how to add rows/columns such as:
paramGrid.RowDefinitions.Add(new RowDefinition());
TextBox tb = new TextBox();
tb.Text = "Sample";
tb.Name = "textBox";
paramGrid.Children.Add(tb);
Grid.SetColumn(tb, 0);
Grid.SetRow(tb, 2);
The above adds a TextBox to the new row.
My question is: How would I go about accessing it now? I need to query the .Text property of the TextBox on the new row.

Keep a ref to the textbox:
private TextBox m_Tb;
...
m_Tb = new TextBox();
m_Tb.Text = "Sample";
m_Tb.Name = "textBox";
....
something something = m_Tb.Text;
Find it in the grid's Children collection:
var tb = (TextBox)paramGrid.Children[0];
something something = tb.Text;
Obviously [0] will only work if the text box is either the only child in the grid or the first one.

Related

How can I Load XAML dynamically in code behind

One way to add a dynamic control in code-behind is something like this (obviously):
Button thisButton = new Button();
thisButton.Name = "somecool_btn";
thisButton.Content = "Click Me";
someStackPanel.Children.Add(thisButton);
I used to know how to do this using XAML in code behind for more complex dynamic control creation. Basically by creating a string with xaml and then adding it to the StackPanel (or some other UI element)....
string someXaml = #"<Button x:Name='somecool_btn' Content='Click Me' Width='100' Height='29'></Button>";
Now add someXaml to a StackPanel or something...
You can use XamlReader.Parse(https://learn.microsoft.com/dotnet/api/system.windows.markup.xamlreader.parse?view=netcore-3.1). Below is actual usage of it in my previous project(It's messy).
private readonly string gridTemplate = #"
<Grid xmlns='http://schemas.microsoft.com/winfx/2006/xaml/presentation'
xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'
Margin=""0,27,0,0"">
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Rectangle Height=""3"" Grid.Column=""0"" Margin=""0,19,0,0"" VerticalAlignment=""Top"" HorizontalAlignment=""Right"" Fill=""#FFD8D8D8"" Width=""700"" StrokeDashArray=""1"" StrokeThickness=""3"" Stroke=""{Binding RelativeSource={RelativeSource Self}, Path=Fill}""/>
<Rectangle Height=""3"" Grid.Column=""1"" Margin=""0,19,0,0"" VerticalAlignment=""Top"" HorizontalAlignment=""Right"" Fill=""#FFD8D8D8"" Width=""700"" StrokeDashArray=""1"" StrokeThickness=""3"" Stroke=""{Binding RelativeSource={RelativeSource Self}, Path=Fill}""/>
<StackPanel Grid.ColumnSpan=""2"" HorizontalAlignment= ""Center"" VerticalAlignment= ""Top"" Margin= ""0"" Height= ""126"" >
<Grid Margin=""70,0,70,40"">
<Ellipse Fill = ""#FF555555"" HorizontalAlignment=""Left"" Width=""41"" Height=""41""/>
<TextBlock FontFamily = ""{DynamicResource keyBoldFont}"" Foreground=""White"" HorizontalAlignment=""Center"" VerticalAlignment=""Center"" Text=""99"" FontSize=""20""/>
</Grid>
<TextBlock FontFamily = ""{DynamicResource keyBoldFont}"" FontSize= ""20"" HorizontalAlignment= ""Center"" Foreground= ""#FF555555"" TextWrapping= ""Wrap""/>
</StackPanel >
</Grid >";
private Grid MakeNewProgressItem(int gridColumn, string text)
{
try
{
var resBase = System.Windows.Markup.XamlReader.Parse(gridTemplate) as Grid;
var rectangleL = resBase.Children[0] as Rectangle;
var rectangleR = resBase.Children[1] as Rectangle;
var sp = resBase.Children[2] as StackPanel;
var gr2 = sp.Children[0] as Grid;
var ellipse = gr2.Children[0] as Ellipse;
var num = gr2.Children[1] as TextBlock;
var tb = sp.Children[1] as TextBlock;
Grid.SetColumn(resBase, gridColumn);
...

Fill out grid, then extend downwards in WPF

[enter image description here][1]I want to make an application that shows all files in a folder as buttons, so I can open them from the application. So they are getting added dynamically. But I have a problem: I need to show them like a grid, side by side. And if there are more than 9 files it needs to scroll down. I have tried with the layout:
<Grid Name="buttonGrid">
<ScrollViewer VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Disabled">
<Grid Height="450" Width="800" Background="White">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="1*"/>
<ColumnDefinition Width="1*"/>
<ColumnDefinition Width="1*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="1*"/>
<RowDefinition Height="1*"/>
<RowDefinition Height="1*"/>
</Grid.RowDefinitions>
</Grid>
</ScrollViewer>
</Grid>
And I C#:
public partial class PlayGame : Page
{
public PlayGame()
{
InitializeComponent();
AddButtons();
}
//Add buttons to grid
private void AddButtons()
{
var folderName = $"{AppDomain.CurrentDomain.BaseDirectory}games";
if (!Directory.Exists(folderName))
{
Directory.CreateDirectory(folderName);
}
var allFiles = Directory.GetFiles(folderName);
foreach (string fileName in allFiles)
{
var fi = new FileInfo(fileName);
Button newBtn = new Button
{
Content = fi.Name,
Name = "Button" + fi.Name.Replace(".", "_"),
BorderThickness = new Thickness(0)
};
Grid.SetRow(newBtn, 0);
Grid.SetColumn(newBtn, 0);
newBtn.Click += OpenFile;
buttonGrid.Children.Add(newBtn);
}
}
}
And it works partly... The buttons are getting added, and they work, but they are stacked on each other. So how would i fix that?
I want it like this: https://i.stack.imgur.com/6EUKS.png
But dynamically for each file, there is in a folder. And if there are more than 9 files extend downwards so the scrollviewer comes into action.
Try using
<ScrollViewer Height="300">
<WrapPanel Name="listView" Orientation="Horizontal">
</WrapPanel>
</ScrollViewer>
Your very close.
Try increasing the column
Grid.SetColumn(newBtn, i);
for every iteration.
Then you can also set the row
Grid.SetRow(newBtn, i % 3);
to add a new row every three buttons.
Now if you want a new row you can add it with this command:
buttonGrid.RowDefinitions.Add(new RowDefinition());

Set Dockpanel size in grid programmatically

My goal is to programmatically set a DockPanel size.
I want it to span from Grid.Column=1, Grid.Row=1, Grid.RowSpan=5
And I know hot to set it statically in xaml, but not in c#.
Explanation to code: In xaml I made a 1row 1 column grid with some textfields and a button in the DockPanel. In when I press the button it should create a grid with as many column/rows as I wrote in the textfields. Then name each column and each row. And know I want to create a Dockpanel on some of these fields but for that I must define where it starts and how far it spans. This is where the problem is.
here is my xaml code how I made it:
<Grid Name="MainWindowGrid">
<Grid.ColumnDefinitions>
<ColumnDefinition Name="DockPanel"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition/>
</Grid.RowDefinitions>
<DockPanel Background="LightSalmon" Grid.Row="0" Grid.Column="0" Grid.RowSpan="8">
<StackPanel>
<TextBox Name="txtColums" Text="16"/>
<TextBox Name="txtRows" Text="8"/>
<TextBox Name="txtWindowHeight" Text="800"/>
<TextBox Name="txtWindowWidth" Text="1600"/>
<Button x:Name="ButtonCreate" Content="Create" Click="ButtonCreate_Click"/>
</StackPanel>
</DockPanel>
<ContentControl Content="{Binding}"/>
</Grid>
And my C# code what I have so far:
Methods Methods = new Methods();
Methods.CreateField(MainWindowGrid, txtColums, txtRows, txtWindowHeight, txtWindowWidth, MainWindow1);
int GridColumnCount = MainWindowGrid.ColumnDefinitions.Count;
int GridRowCount = MainWindowGrid.RowDefinitions.Count;
for (int a = 1; a < GridColumnCount; a++)
{
MainWindowGrid.ColumnDefinitions.ElementAt(a).Name = "C" + a;
}
for (int a = 1; a < GridRowCount; a++)
{
MainWindowGrid.RowDefinitions.ElementAt(a).Name = "R" + a;
}
var converter = new System.Windows.Media.BrushConverter();
var brush1 = (Brush)converter.ConvertFromString("#FFFFFFF0");
DockPanel myDockPanel = new DockPanel();
myDockPanel.Background = brush1;
myDockPanel.
At the very end I want to be able to set at which row/column the dockpanel should be and then span it, but I sadly do not know how.
You could use the following methods to set the Grid.Column, Grid.Row and Grid.RowSpan attached properties of myDockPanel:
Grid.SetColumn(myDockPanel, 1); //= <DockPanel ... Grid.Column = "1"
Grid.SetRow(myDockPanel, 1); //= <DockPanel ... Grid.Row = "1"
Grid.SetRowSpan(myDockPanel, 8); //= <DockPanel ... Grid.RowSpan = "8"

Cannot dynamically create columns/rows in WPF

I want to be able to dynamically set a window's size in WPF, and then create as many columns and rows in a grid as I want.
I've created a method for it but it does not seem to work. I also added a border in XAML to see if there are columns and rows but I only see one square.
Also, it throws no error whatsoever.
This is my method:
public void CreateField(Grid MainGrid, TextBox Columns, TextBox Rows, TextBox WHeight, TextBox WWidth, MainWindow MainWindow)
{
int ColumnCount = Int32.Parse(Columns.Text);
int RowCount = Int32.Parse(Rows.Text);
int WindowHeight = Int32.Parse(WHeight.Text);
int WindowWidth = Int32.Parse(WWidth.Text);
MainWindow.MainWindow1.Height = WindowHeight;
MainWindow.MainWindow1.Width = WindowWidth;
for(int a = 0; a <= ColumnCount; a++){
ColumnDefinition c = new ColumnDefinition();
c.Width = new GridLength(WindowWidth / ColumnCount, GridUnitType.Pixel);
MainGrid.ColumnDefinitions.Add(c);
}
for (int a = 0; a <= RowCount; a++)
{
RowDefinition r = new RowDefinition();
r.Height = new GridLength(WindowHeight / RowCount, GridUnitType.Pixel);
MainGrid.RowDefinitions.Add(r);
}
}
In XAML I have this good with only 1 column and 1 row and a dockpanel for the textboxes and buttons.
<Border BorderBrush="Black" BorderThickness="2">
<Grid Name="MainWindowGrid">
<Grid.ColumnDefinitions>
<ColumnDefinition Name="DockPanel"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition/>
</Grid.RowDefinitions>
<DockPanel Background="LightSalmon" Grid.Row="0" Grid.Column="0" Grid.RowSpan="8">
<StackPanel>
<TextBox Name="txtColums" Text="16"/>
<TextBox Name="txtRows" Text="8"/>
<TextBox Name="txtWindowHeight" Text="800"/>
<TextBox Name="txtWindowWidth" Text="1600"/>
<Button x:Name="ButtonCreate" Content="Create" Click="ButtonCreate_Click"/>
</StackPanel>
</DockPanel>
<ContentControl Content="{Binding}"/>
</Grid>
</Border>
And according to the parameters written here the method should be executed on button click. But instead of a grid with 16 columns and 8 rows, I only get 1 column 1 row. (you can see the border at the edge)
So what am I doing wrong here? I have no real experience with grids whatsoever, and I am pretty clueless. Hope someone can help me out.
EDIT:
The suggestion of to activate MainGrid.ShowGridLines as said by ASh worked. Did not know about this functionality. As it turns out i do have succesfully created the columns and rows. I thought it not to work because i tried to paint a field in the grid with a color which did not work. Now i wonder, why this does not work as i thought this to be correct code.
var converter = new System.Windows.Media.BrushConverter();
var brush1 = (Brush)converter.ConvertFromString("#FFFFFFF0");
DockPanel myDockPanel = new DockPanel();
Grid.SetColumn(myDockPanel, 3);
Grid.SetRow(myDockPanel, 3);
myDockPanel.Background = brush1;
There was a lot going wrong here and its a magical jar of wonderment why you wanted to do this, however this should point you in a better direction
Some Modifications
Dedicated Grid
Get the ActualHeight and ActualWidth to use
Set GridLines true, so you can see whats happening
Set the Grid alignments to Stretch
Don't alter the size of the window
Xaml
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Border Grid.Row="0"
Grid.Column="0"
BorderBrush="Black"
BorderThickness="2">
<DockPanel Grid.RowSpan="8" Background="LightSalmon">
<StackPanel>
<TextBox Name="txtColums" Text="16" />
<TextBox Name="txtRows" Text="8" />
<TextBox Name="txtWindowHeight" Text="800" />
<TextBox Name="txtWindowWidth" Text="1600" />
<Button x:Name="ButtonCreate"
Click="ButtonCreate_OnClick"
Content="Create" />
</StackPanel>
</DockPanel>
</Border>
<Grid Name="MainWindowGrid"
Grid.Row="1"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
ShowGridLines="True" />
</Grid>
Code behind
public void CreateField(Grid MainGrid, TextBox Columns, TextBox Rows) // TextBox WHeight, TextBox WWidth, MainWindow MainWindow)
{
var ColumnCount = int.Parse(Columns.Text);
var RowCount = int.Parse(Rows.Text);
var width = MainGrid.ActualWidth;
var height = MainGrid.ActualHeight;
for (var a = 0; a <= ColumnCount; a++)
{
var c = new ColumnDefinition();
c.Width = new GridLength(width / ColumnCount, GridUnitType.Pixel);
MainGrid.ColumnDefinitions.Add(c);
}
for (var a = 0; a <= RowCount; a++)
{
var r = new RowDefinition();
r.Height = new GridLength(height / RowCount, GridUnitType.Pixel);
MainGrid.RowDefinitions.Add(r);
}
}
private void ButtonCreate_OnClick(object sender, RoutedEventArgs e)
{
CreateField(MainWindowGrid, txtColums, txtRows);
}
grid layout is correct. set MainGrid.ShowGridLines=true; to see it
to see dynamically created control you should add it to grid:
MainGrid.Children.Add(myDockPanel);
since grid rows have equal height and columns have equal width, the following lines can be safely removed:
r.Height = new GridLength(WindowHeight / RowCount, GridUnitType.Pixel);
c.Width = new GridLength(WindowWidth / ColumnCount, GridUnitType.Pixel);
if Width/Height is not set, it is defaulted to * which means Grid will size them equally.
as an alternative UniformGrid can be used:
AnotherMainGrid = new UnifromGrid {Rows = RowCount, Columns = ColumnCount };
but in this case child elements must be added consequtively

Drawing a Linked List using GridView at run time - How to perform Data Binding?

I'm building a C# WPF app (for learning purposes) that draws a linked list based on the data input by the user. I've created AddItem/DeleteItem buttons and corresponding text boxes. Wen user enters an item and Presses Add Item button, the corresponding element is to be drawn, with red line separaters between two elements.
I'm using GridView to display the linked list elements.
Corresponding XAML code is below :
<Grid x:Name="ListDrawGrid">
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="2*" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
</Grid>
I'm currently using C# code to populate data into these elements like below. The below function is called whenever "Add" Button is pressed and new data is inserted into the linked list (ILinkedList is the interface to my custom LinkedList class which maintains the actual list).
public void DrawList(ILinkedList list)
{
int col_index = 0;
int row_index = 1;
GridDrawArea.Children.Clear();
foreach (var i in list)
{
if (col_index >= MaxCols-1)
{
break;
}
TextBlock t = new TextBlock()
{
Text = i,
FontSize = 15,
FontWeight = FontWeights.Bold,
//Width = 15,
HorizontalAlignment = HorizontalAlignment.Left,
//VerticalAlignment = VerticalAlignment.Stretch
};
Grid.SetRow(t,row_index);
Grid.SetColumn(t, col_index);
col_index++;
GridDrawArea.Children.Add(t);
Path line = new Path
{
HorizontalAlignment = HorizontalAlignment.Stretch,
// VerticalAlignment = VerticalAlignment.Stretch,
Stroke = Brushes.Red,
StrokeThickness = 4,
Visibility = Visibility.Visible,
Stretch = Stretch.Fill,
};
LineGeometry lg = new LineGeometry();
lg.StartPoint = new Point(0,col_index);
lg.EndPoint = new Point (0,col_index + 1);
line.Data = lg;
Grid.SetRow(line, row_index);
Grid.SetColumn(line, col_index);
col_index++;
GridDrawArea.Children.Add(line);
}
TextBlock tnull = new TextBlock()
{
Text = "NULL",
FontSize = 15,
//FontWeight = FontWeights.Bold,
HorizontalAlignment = HorizontalAlignment.Stretch,
VerticalAlignment = VerticalAlignment.Stretch,
//Width = 15,
};
Grid.SetRow(tnull, row_index);
Grid.SetColumn(tnull, col_index);
GridDrawArea.Children.Add(tnull);
}
But I feel this is not the correct way of doing things. I'm looking for a way to bind the Grid to the linked list backend code such that, the data is updated whenever a new element is added. If I've to do the same using Data Binding, how should I go about it ? If you need any other information from my end , please let me know.
NOTE: ListDrawGrid and GridDrawArea are the same. I've two different vars as they are in different classes. ListDrawGrid is in the main....xaml.cs and GridDrawArea is in another class and it's initialized with ListDrawGrid at init time.

Categories