I have a grid. I have to define each column and row manually, like this:
<Window x:Class="GridBuild"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="GridBuild" Height="300" Width="300">
<Grid>
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
</Grid>
I want to define the number of rows and columns with a single line, something like this:
<Window x:Class="GridBuild"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="GridBuild" Height="300" Width="300">
<Grid>
<Grid.NumberOfRows="2"/>
<Grid.NumberOfColumns/>
</Grid>
</Window>
The grid-auto-rows CSS property is part of the CSS Grid Layout specification, specifying the size of the grid rows that were created without having an explicit size. In other words, this property sets the size of implicit rows and any other rows that have not been explicitly sized in the grid-template-rows property.
Note: The grid-column property is a shorthand property for the grid-column-start and the grid-column-end properties. To place an item, you can refer to line numbers, or use the keyword "span" to define how many columns the item will span.
To specify the number of columns of the grid and the widths of each column, the CSS property grid-template-columns is used on the grid container. The number of width values determines the number of columns and each width value can be either in pixels( px ) or percentages(%).
A grid area is one or more grid cells that make up a rectangular area on the grid. Grid areas are created when you place an item using line-based placement or when defining areas using named grid areas. Grid areas must be rectangular in nature; it is not possible to create, for example, a T- or L-shaped grid area.
What you describe is called UniformGrid
. It has Columns
and Rows
properties by which you can set the number of rows or columns that you want.
If you don't set these properties, the UniformGrid
will try to layout the children as close to a square as it can. In this situation, it prefers to increase the number of columns before increasing the number of rows.
It's an obscure panel, but it's extremely powerful when used correctly.
I propose deriving from Grid
and adding these properties to it like following:
public class GridEx : Grid
{
public int NumberOfRows
{
get { return RowDefinitions.Count; }
set
{
RowDefinitions.Clear();
for (int i = 0; i < value; i++)
RowDefinitions.Add(new RowDefinition());
}
}
public int NumberOfColumns
{
get { return ColumnDefinitions.Count; }
set
{
ColumnDefinitions.Clear();
for (int i = 0; i < value; i++)
ColumnDefinitions.Add(new ColumnDefinition());
}
}
}
Now it can be used as following:
<local:GridEx NumberOfRows="3" NumberOfColumns="2">
<TextBox>some text</TextBox>
<TextBox Grid.Row="1">some text</TextBox>
<TextBox Grid.Row="2">some text</TextBox>
<TextBox Grid.Column="1">some text</TextBox>
<TextBox Grid.Row="1" Grid.Column="1">some text</TextBox>
<TextBox Grid.Row="2" Grid.Column="1">some text</TextBox>
</local:GridEx>
Works in designer as well by the way :)
The challenge here is to set different Width, Height etc. for different rows and columns. I have a nice thought how to do this. Also it is possible to automate assigning Grid.Row and Grid.Column. Think of it :)
The above answer by EvAlex will work, but only if you don't want to set the number of column/rows using data binding.
public class GridEx : Grid
{
public int NumberOfRows
{
get { return RowDefinitions.Count; }
set
{
RowDefinitions.Clear();
for (int i = 0; i < value; i++)
RowDefinitions.Add(new RowDefinition());
}
}
public int NumberOfColumns
{
get { return ColumnDefinitions.Count; }
set
{
ColumnDefinitions.Clear();
for (int i = 0; i < value; i++)
ColumnDefinitions.Add(new ColumnDefinition());
}
}
}
If you do want to set these via data binding (like I do), then with the above solution the compiler will complain because it needs DependencyProperties
for that. A DependencyProperty
can be implemented (using C# 6's nameof
operator) as follows (a quick way to insert it is using the snippet propdp):
public int Columns
{
get { return (int) GetValue(ColumnsDependencyProperty); }
set { SetValue(ColumnsDependencyProperty, value); }
}
public static readonly DependencyProperty ColumnsDependencyProperty =
DependencyProperty.Register(nameof(Columns), typeof(int), typeof(GridEx), new PropertyMetadata(0));
But this way you can't execute the necessary logic to add the necessary number of RowDefinitions
. To solve this, define a DependencyPropertyDescriptor
for each DependencyProperty
and add an AddValueChanged
call with the necessary logic to it in your custom class's constructor. The result per propery is then (using C# 6's null-conditional operator ?.
):
public int Columns
{
get { return (int) GetValue(ColumnsDependencyProperty); }
set { SetValue(ColumnsDependencyProperty, value); }
}
public static readonly DependencyProperty ColumnsDependencyProperty =
DependencyProperty.Register(nameof(Columns), typeof(int), typeof(GridEx), new PropertyMetadata(0));
DependencyPropertyDescriptor ColumnsPropertyDescriptor = DependencyPropertyDescriptor.FromProperty(ColumnsDependencyProperty, typeof(GridEx));
public GridEx()
{
ColumnsPropertyDescriptor?.AddValueChanged(this, delegate
{
ColumnDefinitions.Clear();
for (int i = 0; i < Columns; i++)
ColumnDefinitions.Add(new ColumnDefinition());
});
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With