How to setup a grid as template for an Items control?

You can use a ListView

<ListView ItemsSource="{Binding MyList}">
    <ListView.View>
        <GridView>
            <GridView.ColumnHeaderContainerStyle>
                <Style TargetType="{x:Type GridViewColumnHeader}">
                    <Setter Property="Visibility" Value="Collapsed" />
                </Style>
            </GridView.ColumnHeaderContainerStyle>
            <GridViewColumn 
                Header="" 
                Width="Auto" 
                DisplayMemberBinding="{Binding Header}"/>
            <GridViewColumn 
                Header="" 
                DisplayMemberBinding="{Binding Value}"/>
        </GridView>
    </ListView.View>
</ListView>

the ColumnHeaderContainerStyle hides the GridViewHeader


There are multiple problems here for an ItemsControl:

  • Getting your first column to match the width of the largest item
  • Generating a dynamic number of rows
  • Generating more than one item for each iteration of the ItemsControl

The last one is really the biggest problem, because an ItemsControl wraps each ItemTemplate in a ContentPresenter, so there is no default way of creating more than one item in the panel for each Iteration of the ItemsControl. Your end result would look like this:

<Grid>
    ...

    <ContentPresenter>
        <Label Content="{Binding Items[0].Header}"/>
        <TextBox Text="{Binding Items[0].Content}" Grid.Column="1"/>
    </ContentPresenter>
    <ContentPresenter>
        <Label Content="{Binding Items[1].Header}" Grid.Row="1"/>
        <TextBox Text="{Binding Items[1].Content}" Grid.Row="1" Grid.Column="1"/>
    </ContentPresenter>
    <ContentPresenter>
        <Label Content="{Binding Items[2].Header}" Grid.Row="2"/>
        <TextBox Text="{Binding Items[2].Content}" Grid.Row="2" Grid.Column="1"/>
    </ContentPresenter>
</Grid> 

My best suggestion would be to create an ItemTemplate that contains a 1x2 Grid, and use Grid.IsSharedSizeScope to make the width of the first column shared. (The ItemsPanelTemplate would remain the default StackPanel.)

This way, the end result would look like this:

<StackPanel>
    <ContentPresenter>
        <Grid IsSharedSizeScope="True">
            <Grid.ColumnDefinitions>
                <ColumnDefinition SharedSizeGroup="ColumnOne" />
                <ColumnDefinition Width="*" />
            </Grid.ColumnDefinitions>
            <Label Content="{Binding Header}"/>
            <TextBox Text="{Binding Content}" Grid.Column="1"/>
        </Grid>
    </ContentPresenter>
    <ContentPresenter>
        <Grid IsSharedSizeScope="True">
            <Grid.ColumnDefinitions>
                <ColumnDefinition SharedSizeGroup="ColumnOne" />
                <ColumnDefinition Width="*" />
            </Grid.ColumnDefinitions>
            <Label Content="{Binding Header}"/>
            <TextBox Text="{Binding Content}" Grid.Column="1"/>
        </Grid>
    </ContentPresenter>
    ...
</StackPanel>