plusheen
plusheen

Reputation: 1436

XAML Data Binding in a nested Grid

I have created a nested grid in XAML, which currently looks like this:

<Grid x:Name="mainGrid" >        
    <Grid.RowDefinitions>
        <RowDefinition/>
        <RowDefinition/>
    </Grid.RowDefinitions>
    <Grid.ColumnDefinitions>
        <ColumnDefinition/>
        <ColumnDefinition/>
    </Grid.ColumnDefinitions>

    <Grid Grid.Row="{Binding Row}" Grid.Column="{Binding Col}">
        <Grid.RowDefinitions>
            <RowDefinition Height="0.1*"/>
            <RowDefinition/>
        </Grid.RowDefinitions>
        <TextBlock Text="{Binding Title}" VerticalAlignment="Bottom" HorizontalAlignment="Center" Grid.Row="0" FontWeight="Bold" TextDecorations="Underline"/>
        <ListView ItemsSource="{Binding Names}" Grid.Row="1"/>
    </Grid>

</Grid>

My aim is to populate 4 Grids that follow the template of the inner Grid. I have attempted this by using the following code behind:

List<Test> tests = new List<Test>();

for (int i = 0; i < 2; i++)
{
     for (int j = 0; j < 2; j++)
     {
          Test t = new Test();
          t.Title = i + "\t" + j;
          t.Row = i;
          t.Col = j;
          tests.Add(t);
     }
}

mainGrid.DataContext = tests;

And the class definition:

class Test
{
    public string Title { get; set; }
    public int Row { get; set; }
    public int Col { get; set; }
    public ObservableCollection<string> Names
    {
        get
        {
            return new ObservableCollection<string>() { "A", "B", "C", "D", "E", "F", "G", "H", "I", "J"};
        }   
    }
}

My thoughts here were that I'd have 4 objects with Row/Col definitions for each segment of the outer Grid definition (0,0 & 0,1 & 1,0 & 1,1). The inner Grid would serve as a template like an ItemTemplate in a ListView. However only the top (0,0) Grid is populated.

What steps should I take so that the inner Grid behaves like a template and all 4 Grids are created and populated?

Upvotes: 3

Views: 1609

Answers (1)

dkozl
dkozl

Reputation: 33384

Use ItemsControl, where ItemsSource is a list of Test, and populate ItemsPanel with outer Grid and ItemTemplate with inner Grid

<ItemsControl ItemsSource="{Binding}">
    <ItemsControl.ItemsPanel>
        <ItemsPanelTemplate>
            <Grid>
                <Grid.RowDefinitions>
                    <RowDefinition/>
                    <RowDefinition/>
                </Grid.RowDefinitions>
                <Grid.ColumnDefinitions>
                    <ColumnDefinition/>
                    <ColumnDefinition/>
                </Grid.ColumnDefinitions>
            </Grid>
        </ItemsPanelTemplate>
    </ItemsControl.ItemsPanel>
    <ItemsControl.ItemContainerStyle>
        <Style TargetType="{x:Type ContentPresenter}">
            <Setter Property="Grid.Row" Value="{Binding Row}"/>
            <Setter Property="Grid.Column" Value="{Binding Col}"/>
        </Style>
    </ItemsControl.ItemContainerStyle>
    <ItemsControl.ItemTemplate>
        <DataTemplate>
            <Grid>
                <Grid.RowDefinitions>
                    <RowDefinition Height="0.1*"/>
                    <RowDefinition/>
                </Grid.RowDefinitions>
                <TextBlock Text="{Binding Title}" VerticalAlignment="Bottom" HorizontalAlignment="Center" Grid.Row="0" FontWeight="Bold" TextDecorations="Underline"/>
                <ListView ItemsSource="{Binding Names}" Grid.Row="1"/>
            </Grid>
        </DataTemplate>
    </ItemsControl.ItemTemplate>
</ItemsControl>

and because ItemsControl will wrap item in ContentPresenter you need to move Grid.Column and Grid.Row bindings to ItemContainerStyle

EDIT

ItemsControl is most basic control to display list of something. Controls like ListBox, ListView, ComboBox, DataGrid and even MenuItem they all inherit from ItemsControl adding more functionality on top like selection or column view.

ItemsPanel defines how the general items' container will look, and ItemTemplate defines how each item in the collection will look.

Each ItemsControl will have its item container type. For ListBox it will be ListBoxItem, for ListView it will be ListViewItem and so on and for ItemsControl it's ContentPresenter. It's just a visual container where each item of the list is put as a content, and then - according to hierarchy MSDN: Remarks section - transformed to visual. In the visual tree this container is direct child of the items panel so things list Grid.Column and/or Grid.Row must be set against it. Also for example for ListBox it's ListBoxItem that holds IsSelected property. And the way to change that container or get data of the container is via ItemContainerStyle.

Upvotes: 4

Related Questions