Search code examples
wpfdynamically-generatedwpf-grid

Dynamically added elements are not displayed properly in a dynamically adjusted grid


I've got a ItemsControl which should display Images in a Grid.

The ItemsControl looks like the following:

<ItemsControl x:Name="ICGridThumbnails">
    <ItemsControl.ItemsPanel>
        <ItemsPanelTemplate>
            <Grid ShowGridLines="True" Name="GThumbnails" Loaded="GThumbnails_Loaded" />
        </ItemsPanelTemplate>
    </ItemsControl.ItemsPanel>
    <ItemsControl.ItemTemplate>
        <DataTemplate>
            <Image Grid.Row="{Binding GridRow}" Grid.Column="{Binding GridColumn}" Margin="{Binding Margin}" RenderOptions.BitmapScalingMode="NearestNeighbor" RenderOptions.EdgeMode="Aliased" Source="{Binding BitmapSource}"></Image>
        </DataTemplate>
    </ItemsControl.ItemTemplate>
</ItemsControl>

Since I want to load a variable amount of elements into the grid, I'm not able to define the rows and columns in the markup.

The Bindings GridRow and GridColumn are calculated in the code behind:

int countPerRow = (int)Math.Floor(Application.Current.MainWindow.ActualWidth / ThumbnailBar.ThumbnailWidthLarge);

double marginWidth = (Application.Current.MainWindow.ActualWidth - (countPerRow * ThumbnailBar.ThumbnailWidthLarge)) / (countPerRow - 1);

if (page % countPerRow == 0) {
    item.Margin = new Thickness(0, 10, 0, 0);
} else {
    item.Margin = new Thickness(marginWidth, 10, 0, 0);
}

item.GridRow = (int)Math.Floor((double)((page - 1) / countPerRow));
item.GridColumn = (page % countPerRow) - 1;

Thumbs.LargeThumbnails[page] = item;
ICGridThumbnails.ItemsSource = null;
ICGridThumbnails.ItemsSource = Thumbs.LargeThumbnails;

item is a object with the properties GridColumn, GridRow and BitmapSource.

After calculating all of these objects and set the array to the ItemsSource I'm going to calculate the number of rows and columns:

private void GThumbnails_Loaded(Object sender, RoutedEventArgs e) {
    _GThumbnails = (Grid)sender;
    RearrangeThumbnailGrid();
}

private void RearrangeThumbnailGrid() {
    int countPerRow = (int)Math.Floor(Application.Current.MainWindow.ActualWidth / ThumbnailBar.ThumbnailWidthLarge);
    _GThumbnails.ColumnDefinitions.Clear();
    _GThumbnails.RowDefinitions.Clear();

    // Columns
    for (int i = 0; i < countPerRow; ++i) {
        ColumnDefinition cd = new ColumnDefinition();
        cd.Width = new GridLength(141);
        _GThumbnails.ColumnDefinitions.Add(cd);
    }

    // Rows
    for (int i = 0; i < (Thumbs.LargeThumbnails.Length / countPerRow) + 1; ++i) {
        RowDefinition rd = new RowDefinition();
        rd.Height = new GridLength(200);
        _GThumbnails.RowDefinitions.Add(rd);
    }
}

As can be seen on my screenshot, all Items are loaded into the VisualTree and they have the correct Column and Row values. Also the grid will be displayed correctly. The BitmapSource property seems to work properly because one can see a Image (the 35 on white background) on my screenshot.

The only problem is that all items seem to be displayed in the "first" cell in the left upper corner. It also may be possible that the values for Row and Column are ignored. enter image description here

I tried to use suggestions from here, but that doesn't work.


Solution

  • Set the Grid.Row and Grid.Column attached properties of the ItemContainer:

    <ItemsControl x:Name="ICGridThumbnails">
        <ItemsControl.ItemContainerStyle>
            <Style TargetType="ContentPresenter">
                <Setter Property="Grid.Row" Value="{Binding GridRow}" />
                <Setter Property="Grid.Column" Value="{Binding GridColumn}" />
            </Style>
        </ItemsControl.ItemContainerStyle>
        <ItemsControl.ItemsPanel>
            <ItemsPanelTemplate>
                <Grid ShowGridLines="True" Name="GThumbnails" Loaded="GThumbnails_Loaded" />
            </ItemsPanelTemplate>
        </ItemsControl.ItemsPanel>
        <ItemsControl.ItemTemplate>
            <DataTemplate>
                <Image Margin="{Binding Margin}" RenderOptions.BitmapScalingMode="NearestNeighbor" RenderOptions.EdgeMode="Aliased" Source="{Binding BitmapSource}"></Image>
            </DataTemplate>
        </ItemsControl.ItemTemplate>
    </ItemsControl>