Controls

Grid

Grid is the most flexible general-purpose layout panel in InkkSlinger. It arranges children into rows and columns, supports pixel, auto, and star sizing, and lets each child choose its cell with the attached properties Grid.Row, Grid.Column, Grid.RowSpan, and Grid.ColumnSpan.

Quick start

Use Grid when you need structured two-dimensional layout. It is the right default for headers plus content, dashboards, forms, sidebars, dialogs, and any screen where rows and columns matter.

Minimal two-row layout

<Grid>
  <Grid.RowDefinitions>
    <RowDefinition Height="Auto" />
    <RowDefinition Height="*" />
  </Grid.RowDefinitions>

  <TextBlock Grid.Row="0"
             Text="Inventory" />

  <ListBox Grid.Row="1"
           Margin="0,8,0,0" />
</Grid>

Two-column form shell

<Grid>
  <Grid.ColumnDefinitions>
    <ColumnDefinition Width="140" />
    <ColumnDefinition Width="*" />
  </Grid.ColumnDefinitions>
  <Grid.RowDefinitions>
    <RowDefinition Height="Auto" />
    <RowDefinition Height="Auto" />
  </Grid.RowDefinitions>

  <TextBlock Grid.Row="0" Grid.Column="0" Text="Name" Margin="0,0,12,8" />
  <TextBox Grid.Row="0" Grid.Column="1" Margin="0,0,0,8" />

  <TextBlock Grid.Row="1" Grid.Column="0" Text="Email" Margin="0,0,12,0" />
  <TextBox Grid.Row="1" Grid.Column="1" />
</Grid>

Weighted star columns

<Grid>
  <Grid.ColumnDefinitions>
    <ColumnDefinition Width="2*" />
    <ColumnDefinition Width="*" />
  </Grid.ColumnDefinitions>

  <Border Grid.Column="0" Background="#203448" />
  <Border Grid.Column="1" Background="#162330" />
</Grid>

Default recommendation: start with Auto for content-sized rows or columns and * for the area that should absorb the remaining space. That pattern covers most application layouts cleanly.

Definition model

Grid exposes two collections: ColumnDefinitions and RowDefinitions. Each definition controls the size policy for one column or row.

ColumnDefinition

Use Width, MinWidth, MaxWidth, and inspect ActualWidth after arrange when you need the resolved final width.

RowDefinition

Use Height, MinHeight, MaxHeight, and inspect ActualHeight after arrange when you need the resolved final height.

The supported sizing syntax is:

  • Auto sizes to content, then applies min/max constraints.
  • A number such as 120 means a fixed pixel size.
  • * means one share of the remaining space.
  • 2*, 3*, and similar values mean weighted shares of the remaining space.
<Grid.ColumnDefinitions>
  <ColumnDefinition Width="96" />
  <ColumnDefinition Width="Auto" MinWidth="80" />
  <ColumnDefinition Width="2*" />
  <ColumnDefinition Width="*" MaxWidth="220" />
</Grid.ColumnDefinitions>

If you do not declare any column definitions, Grid behaves as though it had one star-sized column. If you do not declare any row definitions, it behaves as though it had one star-sized row.

Placing children in cells

Each child stays in row 0, column 0 by default. Use Grid's attached properties to move it to another cell or let it span across multiple cells.

Grid.Row

Zero-based row index. The default is 0.

Grid.Column

Zero-based column index. The default is 0.

Grid.RowSpan and Grid.ColumnSpan

Positive span lengths. The default is 1.

Basic row and column placement

<Grid>
  <Grid.ColumnDefinitions>
    <ColumnDefinition Width="Auto" />
    <ColumnDefinition Width="*" />
  </Grid.ColumnDefinitions>
  <Grid.RowDefinitions>
    <RowDefinition Height="Auto" />
    <RowDefinition Height="Auto" />
  </Grid.RowDefinitions>

  <TextBlock Grid.Row="0" Grid.Column="0" Text="Server" Margin="0,0,10,8" />
  <TextBox Grid.Row="0" Grid.Column="1" Margin="0,0,0,8" />

  <TextBlock Grid.Row="1" Grid.Column="0" Text="Port" Margin="0,0,10,0" />
  <TextBox Grid.Row="1" Grid.Column="1" />
</Grid>

Span a header across multiple columns

<Grid>
  <Grid.ColumnDefinitions>
    <ColumnDefinition Width="*" />
    <ColumnDefinition Width="*" />
    <ColumnDefinition Width="*" />
  </Grid.ColumnDefinitions>
  <Grid.RowDefinitions>
    <RowDefinition Height="Auto" />
    <RowDefinition Height="*" />
  </Grid.RowDefinitions>

  <Border Grid.Row="0"
          Grid.Column="0"
          Grid.ColumnSpan="3"
          Background="#223245"
          Padding="12"
          Margin="0,0,0,8">
    <TextBlock Text="Operations dashboard" />
  </Border>

  <Border Grid.Row="1" Grid.Column="0" Background="#182636" Margin="0,0,8,0" />
  <Border Grid.Row="1" Grid.Column="1" Background="#162330" Margin="0,0,8,0" />
  <Border Grid.Row="1" Grid.Column="2" Background="#101822" />
</Grid>

Coercion behavior: if a row, column, or span points outside the declared grid range, InkkSlinger coerces it back into the valid range instead of throwing during layout. You should still author valid indexes because coercion is a safety net, not a layout design tool.

How layout is resolved

Grid runs a measure pass to determine how much space rows and columns need, then an arrange pass to place each child into the rectangle defined by its resolved row and column sizes.

Measure pass

Pixel definitions reserve their fixed size immediately. Auto definitions grow to fit child desired size. Star definitions take a weighted share of remaining constrained space.

Arrange pass

The final grid size is divided across the arranged definitions. Each child is then arranged into the summed rectangle of its row and column span.

  • Auto rows and columns can trigger an unconstrained first measure for children in those axes.
  • If the first measurement already fits the final resolved space, Grid avoids remeasuring the child.
  • Min and max constraints are enforced on row and column definitions.
  • When the total requested size exceeds the available size, Grid reduces overflow in star definitions first, then auto, then pixel definitions, while respecting minimums.
<Grid Width="240" Height="100">
  <Grid.ColumnDefinitions>
    <ColumnDefinition Width="Auto" />
    <ColumnDefinition Width="*" />
  </Grid.ColumnDefinitions>
  <Grid.RowDefinitions>
    <RowDefinition Height="Auto" />
    <RowDefinition Height="*" />
  </Grid.RowDefinitions>

  <TextBlock Grid.Row="0" Grid.Column="0" Text="Auto-sized label" />
  <Border Grid.Row="1" Grid.Column="1" Background="#223245" />
</Grid>

In that layout, the top-left content determines the auto row and auto column size, and the remaining width and height flow into the star row and star column.

Behavior that matters in real screens

Auto plus explicit child size

When a child sits in an auto-sized row or column and has an explicit Width or Height, Grid uses that explicit size plus margin to constrain the first measure pass on that axis. This avoids unnecessary remeasure work for fixed-size content.

<Grid>
  <Grid.ColumnDefinitions>
    <ColumnDefinition Width="Auto" />
  </Grid.ColumnDefinitions>
  <Grid.RowDefinitions>
    <RowDefinition Height="Auto" />
  </Grid.RowDefinitions>

  <Button Width="120"
          Height="36"
          Margin="6,4"
          Text="Apply" />
</Grid>

Inspecting resolved sizes

After arrange, each definition reports its final resolved size through ActualWidth or ActualHeight. This is primarily useful for diagnostics, layout tooling, or controls such as GridSplitter that need to work against the current rendered dimensions.

var grid = new Grid();
grid.ColumnDefinitions.Add(new ColumnDefinition { Width = GridLength.Auto });
grid.ColumnDefinitions.Add(new ColumnDefinition { Width = GridLength.Star });

// After measure + arrange:
float left = grid.ColumnDefinitions[0].ActualWidth;
float right = grid.ColumnDefinitions[1].ActualWidth;

Property reference

Grid surface

ColumnDefinitions: ordered collection of ColumnDefinition objects.

RowDefinitions: ordered collection of RowDefinition objects.

Children: inherited from Panel; the visual elements arranged into cells.

Attached properties

Grid.Row: target row index, default 0.

Grid.Column: target column index, default 0.

Grid.RowSpan: number of rows to span, default 1.

Grid.ColumnSpan: number of columns to span, default 1.

ColumnDefinition

Width: GridLength using pixel, auto, or star sizing.

MinWidth: lower size bound, clamped to zero or above.

MaxWidth: upper size bound.

ActualWidth: resolved width after arrange.

RowDefinition

Height: GridLength using pixel, auto, or star sizing.

MinHeight: lower size bound, clamped to zero or above.

MaxHeight: upper size bound.

ActualHeight: resolved height after arrange.

Patterns and examples

Header plus content area

<Grid>
  <Grid.RowDefinitions>
    <RowDefinition Height="Auto" />
    <RowDefinition Height="*" />
  </Grid.RowDefinitions>

  <Border Grid.Row="0"
          Background="#1C2B3A"
          BorderBrush="#33506B"
          BorderThickness="0,0,0,1"
          Padding="12">
    <TextBlock Text="Project Explorer" />
  </Border>

  <TreeView Grid.Row="1" />
</Grid>

Sidebar and main panel

<Grid>
  <Grid.ColumnDefinitions>
    <ColumnDefinition Width="260" />
    <ColumnDefinition Width="*" />
  </Grid.ColumnDefinitions>

  <Border Grid.Column="0"
          Background="#162330"
          BorderBrush="#28445F"
          BorderThickness="0,0,1,0"
          Padding="12" />

  <ContentControl Grid.Column="1"
                  Margin="16,0,0,0" />
</Grid>

Three-column dashboard cards

<Grid>
  <Grid.ColumnDefinitions>
    <ColumnDefinition Width="*" />
    <ColumnDefinition Width="*" />
    <ColumnDefinition Width="*" />
  </Grid.ColumnDefinitions>

  <Border Grid.Column="0" Margin="0,0,12,0" Padding="12" Background="#1B2C3C" />
  <Border Grid.Column="1" Margin="0,0,12,0" Padding="12" Background="#152331" />
  <Border Grid.Column="2" Padding="12" Background="#101A24" />
</Grid>

Form with aligned labels

<Grid>
  <Grid.ColumnDefinitions>
    <ColumnDefinition Width="Auto" />
    <ColumnDefinition Width="*" />
  </Grid.ColumnDefinitions>
  <Grid.RowDefinitions>
    <RowDefinition Height="Auto" />
    <RowDefinition Height="Auto" />
    <RowDefinition Height="Auto" />
  </Grid.RowDefinitions>

  <TextBlock Grid.Row="0" Grid.Column="0" Text="User" Margin="0,0,10,8" />
  <TextBox Grid.Row="0" Grid.Column="1" Margin="0,0,0,8" />

  <TextBlock Grid.Row="1" Grid.Column="0" Text="Password" Margin="0,0,10,8" />
  <PasswordBox Grid.Row="1" Grid.Column="1" Margin="0,0,0,8" />

  <Button Grid.Row="2"
          Grid.Column="1"
          Width="120"
          HorizontalAlignment="Left"
          Text="Sign in" />
</Grid>

Resizable split layout with GridSplitter

<Grid>
  <Grid.ColumnDefinitions>
    <ColumnDefinition Width="220" MinWidth="160" />
    <ColumnDefinition Width="6" />
    <ColumnDefinition Width="*" MinWidth="280" />
  </Grid.ColumnDefinitions>

  <TreeView Grid.Column="0" />

  <GridSplitter Grid.Column="1"
                Width="6"
                HorizontalAlignment="Stretch" />

  <ContentControl Grid.Column="2" />
</Grid>

Notes and pitfalls

Children default to cell 0,0. If multiple children omit Grid.Row and Grid.Column, they all stack into the first cell.

No definitions means one implicit star row and one implicit star column. That is convenient for a simple single-cell layout, but it is easy to forget when you expected a multi-row or multi-column arrangement.

Star sizing depends on finite available space. When the available width or height is unconstrained, star definitions do not magically pick a final size during the early measure phase. They resolve against constrained space during arrange or constrained measure.

Spans are clamped to the grid bounds. Oversized spans do not extend layout beyond the declared row or column count.

Use Grid for two-dimensional structure, not repetition. If you are creating repeated equally sized cells, UniformGrid is usually simpler. If you only need vertical or horizontal stacking, StackPanel is usually the better fit.