-
Notifications
You must be signed in to change notification settings - Fork 2
Why use Name Based Grid?
The WPF grid control is versatile and allows for creating diverse layouts. However, it requires developers to keep track of column and row indices, and it requires developers to update those column and row indices in many places when something in the first few columns or rows of the grid changes.
In the following, a small exemplary user interface for inputting some personal details is created. This example illustrates several situations that you may have run into when using the Grid
control, and shows how in these situations, using NameBasedGrid
is less cumbersome.
With Grid
, developers have to count column and row definitions and explicitly write down the sequential indices for the controls in the grid:
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Label Grid.Column="0" Grid.Row="0" Content="First name:" VerticalAlignment="Center"/>
<TextBox Grid.Column="1" Grid.Row="0" HorizontalAlignment="Stretch"/>
<Label Grid.Column="0" Grid.Row="1" Content="Last name:" VerticalAlignment="Center"/>
<TextBox Grid.Column="1" Grid.Row="1" HorizontalAlignment="Stretch"/>
</Grid>
With NameBasedGrid
, columns and rows can have descriptive names:
<grid:NameBasedGrid>
<grid:NameBasedGrid.ColumnDefinitions>
<ColumnOrRow Name="Lbl" Size="Auto"/>
<ColumnOrRow Name="Ctl" Size="*"/>
</grid:NameBasedGrid.ColumnDefinitions>
<grid:NameBasedGrid.RowDefinitions>
<ColumnOrRow Name="FirstName" Size="Auto"/>
<ColumnOrRow Name="LastName" Size="Auto"/>
</grid:NameBasedGrid.RowDefinitions>
<Label grid:NameBasedGrid.Column="Lbl" grid:NameBasedGrid.Row="FirstName" Content="First name:" VerticalAlignment="Center"/>
<TextBox grid:NameBasedGrid.Column="Ctl" grid:NameBasedGrid.Row="FirstName" HorizontalAlignment="Stretch"/>
<Label grid:NameBasedGrid.Column="Lbl" grid:NameBasedGrid.Row="LastName" Content="Last name:" VerticalAlignment="Center"/>
<TextBox grid:NameBasedGrid.Column="Ctl" grid:NameBasedGrid.Row="LastName" HorizontalAlignment="Stretch"/>
</grid:NameBasedGrid>
To have a control span several (w.l.o.g.) columns in a Grid
, the exact number of spanned columns needs to be counted and supplied:
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Label Grid.Column="0" Grid.Row="0" Content="First name:" VerticalAlignment="Center"/>
<TextBox Grid.Column="1" Grid.Row="0" HorizontalAlignment="Stretch"/>
<Label Grid.Column="0" Grid.Row="1" Content="Last name:" VerticalAlignment="Center"/>
<TextBox Grid.Column="1" Grid.Row="1" HorizontalAlignment="Stretch"/>
<CheckBox Grid.Column="0" Grid.ColumnSpan="2" Grid.Row="2" HorizontalAlignment="Stretch"/>
</Grid>
With NameBasedGrid
, the two outermost columns spanned by the control are indicated by their names instead:
<grid:NameBasedGrid>
<grid:NameBasedGrid.ColumnDefinitions>
<ColumnOrRow Name="Lbl" Size="Auto"/>
<ColumnOrRow Name="Ctl" Size="*"/>
</grid:NameBasedGrid.ColumnDefinitions>
<grid:NameBasedGrid.RowDefinitions>
<ColumnOrRow Name="FirstName" Size="Auto"/>
<ColumnOrRow Name="LastName" Size="Auto"/>
<ColumnOrRow Name="Private" Size="Auto"/>
</grid:NameBasedGrid.RowDefinitions>
<Label grid:NameBasedGrid.Column="Lbl" grid:NameBasedGrid.Row="FirstName" Content="First name:" VerticalAlignment="Center"/>
<TextBox grid:NameBasedGrid.Column="Ctl" grid:NameBasedGrid.Row="FirstName" HorizontalAlignment="Stretch"/>
<Label grid:NameBasedGrid.Column="Lbl" grid:NameBasedGrid.Row="LastName" Content="Last name:" VerticalAlignment="Center"/>
<TextBox grid:NameBasedGrid.Column="Ctl" grid:NameBasedGrid.Row="LastName" HorizontalAlignment="Stretch"/>
<CheckBox grid:NameBasedGrid.Column="Lbl" grid:NameBasedGrid.ExtendToColumn="Ctl" grid:NameBasedGrid.Row="Private" Content="Is private contact" HorizontalAlignment="Stretch"/>
</grid:NameBasedGrid>
With Grid
, retroactively splitting up a (w.l.o.g.) column will affect everything placed already in that column:
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Label Grid.Column="0" Grid.Row="0" Content="First name:" VerticalAlignment="Center"/>
<TextBox Grid.Column="1" Grid.ColumnSpan="2" Grid.Row="0" HorizontalAlignment="Stretch"/>
<Label Grid.Column="0" Grid.Row="1" Content="Last name:" VerticalAlignment="Center"/>
<TextBox Grid.Column="1" Grid.ColumnSpan="2" Grid.Row="1" HorizontalAlignment="Stretch"/>
<CheckBox Grid.Column="0" Grid.ColumnSpan="3" Grid.Row="2" HorizontalAlignment="Stretch"/>
<Label Grid.Column="0" Grid.Row="3" Content="Age:" VerticalAlignment="Center"/>
<TextBox Grid.Column="1" Grid.Row="3" HorizontalAlignment="Stretch"/>
<Button Grid.Column="2" Grid.Row="3" Content="Compute from birth date" HorizontalAlignment="Stretch"/>
</Grid>
With NameBasedGrid
, two new columns can be created with new names, and a virtual column can be used to replace the previous column:
<grid:NameBasedGrid>
<grid:NameBasedGrid.ColumnDefinitions>
<ColumnOrRow Name="Lbl" Size="Auto"/>
<ColumnOrRow Name="SmallCtl" Size="*"/>
<ColumnOrRow Name="Editor" Size="Auto"/>
<VirtualColumnOrRow Name="Ctl" StartAt="SmallCtl" ExtendTo="Editor"/>
</grid:NameBasedGrid.ColumnDefinitions>
<grid:NameBasedGrid.RowDefinitions>
<ColumnOrRow Name="FirstName" Size="Auto"/>
<ColumnOrRow Name="LastName" Size="Auto"/>
<ColumnOrRow Name="Private" Size="Auto"/>
<ColumnOrRow Name="Age" Size="Auto"/>
</grid:NameBasedGrid.RowDefinitions>
<Label grid:NameBasedGrid.Column="Lbl" grid:NameBasedGrid.Row="FirstName" Content="First name:" VerticalAlignment="Center"/>
<TextBox grid:NameBasedGrid.Column="Ctl" grid:NameBasedGrid.Row="FirstName" HorizontalAlignment="Stretch"/>
<Label grid:NameBasedGrid.Column="Lbl" grid:NameBasedGrid.Row="LastName" Content="Last name:" VerticalAlignment="Center"/>
<TextBox grid:NameBasedGrid.Column="Ctl" grid:NameBasedGrid.Row="LastName" HorizontalAlignment="Stretch"/>
<CheckBox grid:NameBasedGrid.Column="Lbl" grid:NameBasedGrid.ExtendToColumn="Ctl" grid:NameBasedGrid.Row="Private" Content="Is private contact" HorizontalAlignment="Stretch"/>
<Label grid:NameBasedGrid.Column="Lbl" grid:NameBasedGrid.Row="Age" Content="Age:" VerticalAlignment="Center"/>
<TextBox grid:NameBasedGrid.Column="SmallCtl" grid:NameBasedGrid.Row="Age" HorizontalAlignment="Stretch"/>
<Button grid:NameBasedGrid.Column="Editor" grid:NameBasedGrid.Row="Age" Content="Compute from birth date" HorizontalAlignment="Stretch"/>
</grid:NameBasedGrid>
With a Grid
, any change to the list of (w.l.o.g.) rows has an effect on subsequent rows, as their indices change and have to be adjusted throughout the grid:
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Label Grid.Column="0" Grid.Row="0" Content="First name:" VerticalAlignment="Center"/>
<TextBox Grid.Column="1" Grid.ColumnSpan="2" Grid.Row="0" HorizontalAlignment="Stretch"/>
<Label Grid.Column="0" Grid.Row="1" Content="Middle name:" VerticalAlignment="Center"/>
<TextBox Grid.Column="1" Grid.ColumnSpan="2" Grid.Row="1" HorizontalAlignment="Stretch"/>
<Label Grid.Column="0" Grid.Row="2" Content="Last name:" VerticalAlignment="Center"/>
<TextBox Grid.Column="1" Grid.ColumnSpan="2" Grid.Row="2" HorizontalAlignment="Stretch"/>
<CheckBox Grid.Column="0" Grid.ColumnSpan="3" Grid.Row="3" HorizontalAlignment="Stretch"/>
<Label Grid.Column="0" Grid.Row="4" Content="Age:" VerticalAlignment="Center"/>
<TextBox Grid.Column="1" Grid.Row="4" HorizontalAlignment="Stretch"/>
<Button Grid.Column="2" Grid.Row="4" Content="Compute from birth date" HorizontalAlignment="Stretch"/>
</Grid>
With NameBasedGrid
, you simply insert the new row definition and the new controls. Nothing else changes:
<grid:NameBasedGrid>
<grid:NameBasedGrid.ColumnDefinitions>
<ColumnOrRow Name="Lbl" Size="Auto"/>
<ColumnOrRow Name="SmallCtl" Size="*"/>
<ColumnOrRow Name="Editor" Size="Auto"/>
<VirtualColumnOrRow Name="Ctl" StartAt="SmallCtl" ExtendTo="Editor"/>
</grid:NameBasedGrid.ColumnDefinitions>
<grid:NameBasedGrid.RowDefinitions>
<ColumnOrRow Name="FirstName" Size="Auto"/>
<ColumnOrRow Name="MiddleName" Size="Auto"/>
<ColumnOrRow Name="LastName" Size="Auto"/>
<ColumnOrRow Name="Private" Size="Auto"/>
<ColumnOrRow Name="Age" Size="Auto"/>
</grid:NameBasedGrid.RowDefinitions>
<Label grid:NameBasedGrid.Column="Lbl" grid:NameBasedGrid.Row="FirstName" Content="First name:" VerticalAlignment="Center"/>
<TextBox grid:NameBasedGrid.Column="Ctl" grid:NameBasedGrid.Row="FirstName" HorizontalAlignment="Stretch"/>
<Label grid:NameBasedGrid.Column="Lbl" grid:NameBasedGrid.Row="MiddleName" Content="Middle name:" VerticalAlignment="Center"/>
<TextBox grid:NameBasedGrid.Column="Ctl" grid:NameBasedGrid.Row="MiddleName" HorizontalAlignment="Stretch"/>
<Label grid:NameBasedGrid.Column="Lbl" grid:NameBasedGrid.Row="LastName" Content="Last name:" VerticalAlignment="Center"/>
<TextBox grid:NameBasedGrid.Column="Ctl" grid:NameBasedGrid.Row="LastName" HorizontalAlignment="Stretch"/>
<CheckBox grid:NameBasedGrid.Column="Lbl" grid:NameBasedGrid.ExtendToColumn="Ctl" grid:NameBasedGrid.Row="Private" Content="Is private contact" HorizontalAlignment="Stretch"/>
<Label grid:NameBasedGrid.Column="Lbl" grid:NameBasedGrid.Row="Age" Content="Age:" VerticalAlignment="Center"/>
<TextBox grid:NameBasedGrid.Column="SmallCtl" grid:NameBasedGrid.Row="Age" HorizontalAlignment="Stretch"/>
<Button grid:NameBasedGrid.Column="Editor" grid:NameBasedGrid.Row="Age" Content="Compute from birth date" HorizontalAlignment="Stretch"/>
</grid:NameBasedGrid>
Just like indices, the number of columns and rows indicated for controls spanning several columns or rows changes once columns or rows are inserted. This is even the case when the inserted columns or rows serve only as a grid-wide spacing and are not supposed to host any controls of their own:
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="3"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="4"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="4"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="4"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="4"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Label Grid.Column="0" Grid.Row="0" Content="First name:" VerticalAlignment="Center"/>
<TextBox Grid.Column="2" Grid.ColumnSpan="2" Grid.Row="0" HorizontalAlignment="Stretch"/>
<Label Grid.Column="0" Grid.Row="2" Content="Middle name:" VerticalAlignment="Center"/>
<TextBox Grid.Column="2" Grid.ColumnSpan="2" Grid.Row="2" HorizontalAlignment="Stretch"/>
<Label Grid.Column="0" Grid.Row="4" Content="Last name:" VerticalAlignment="Center"/>
<TextBox Grid.Column="2" Grid.ColumnSpan="2" Grid.Row="4" HorizontalAlignment="Stretch"/>
<CheckBox Grid.Column="0" Grid.ColumnSpan="4" Grid.Row="6" HorizontalAlignment="Stretch"/>
<Label Grid.Column="0" Grid.Row="8" Content="Age:" VerticalAlignment="Center"/>
<TextBox Grid.Column="2" Grid.Row="8" HorizontalAlignment="Stretch"/>
<Button Grid.Column="3" Grid.Row="8" Content="Compute from birth date" HorizontalAlignment="Stretch"/>
</Grid>
With NameBasedGrid
, it is totally sufficient to insert the spacing columns and rows (without even making up individual names for them!). Nothing else has to be changed:
<grid:NameBasedGrid>
<grid:NameBasedGrid.ColumnDefinitions>
<ColumnOrRow Name="Lbl" Size="Auto"/>
<ColumnOrRow Size="3"/>
<ColumnOrRow Name="SmallCtl" Size="*"/>
<ColumnOrRow Name="Editor" Size="Auto"/>
<VirtualColumnOrRow Name="Ctl" StartAt="SmallCtl" ExtendTo="Editor"/>
</grid:NameBasedGrid.ColumnDefinitions>
<grid:NameBasedGrid.RowDefinitions>
<ColumnOrRow Name="FirstName" Size="Auto"/>
<ColumnOrRow Size="4"/>
<ColumnOrRow Name="MiddleName" Size="Auto"/>
<ColumnOrRow Size="4"/>
<ColumnOrRow Name="LastName" Size="Auto"/>
<ColumnOrRow Size="4"/>
<ColumnOrRow Name="Private" Size="Auto"/>
<ColumnOrRow Size="4"/>
<ColumnOrRow Name="Age" Size="Auto"/>
</grid:NameBasedGrid.RowDefinitions>
<Label grid:NameBasedGrid.Column="Lbl" grid:NameBasedGrid.Row="FirstName" Content="First name:" VerticalAlignment="Center"/>
<TextBox grid:NameBasedGrid.Column="Ctl" grid:NameBasedGrid.Row="FirstName" HorizontalAlignment="Stretch"/>
<Label grid:NameBasedGrid.Column="Lbl" grid:NameBasedGrid.Row="MiddleName" Content="Middle name:" VerticalAlignment="Center"/>
<TextBox grid:NameBasedGrid.Column="Ctl" grid:NameBasedGrid.Row="MiddleName" HorizontalAlignment="Stretch"/>
<Label grid:NameBasedGrid.Column="Lbl" grid:NameBasedGrid.Row="LastName" Content="Last name:" VerticalAlignment="Center"/>
<TextBox grid:NameBasedGrid.Column="Ctl" grid:NameBasedGrid.Row="LastName" HorizontalAlignment="Stretch"/>
<CheckBox grid:NameBasedGrid.Column="Lbl" grid:NameBasedGrid.ExtendToColumn="Ctl" grid:NameBasedGrid.Row="Private" Content="Is private contact" HorizontalAlignment="Stretch"/>
<Label grid:NameBasedGrid.Column="Lbl" grid:NameBasedGrid.Row="Age" Content="Age:" VerticalAlignment="Center"/>
<TextBox grid:NameBasedGrid.Column="SmallCtl" grid:NameBasedGrid.Row="Age" HorizontalAlignment="Stretch"/>
<Button grid:NameBasedGrid.Column="Editor" grid:NameBasedGrid.Row="Age" Content="Compute from birth date" HorizontalAlignment="Stretch"/>
</grid:NameBasedGrid>