Determine ActualHeight of a StackPanel of Grids in code-behind with IsSharedSizeScope applied

462 views Asked by At

I am trying to determine the dimensions needed to display a collection of items in its entirety -- but without having rendered it on the screen.

In most cases, we have a known/fixed width but need to dynamically change the height. The strategy thus far has been to instantiate similar controls in code-behind, set the width, invoke Measure/Arrange, and then use the resulting ActualHeight. This (smelly) strategy has been working relatively well, but it seems to be falling apart when I try to use grid shared size scopes.

This code, in theory, should tell me the height I need to display multiple items in a StackPanel:

var panel = new StackPanel();
Grid.SetIsSharedSizeScope(panel, true);
panel.Width = this.Width;

foreach (var item in this.Items)
{
    var presenter = new ContentPresenter
    {
        Content = item,
        ContentTemplate = <<code to fetch the data template resource>>
    };

    panel.ApplyTemplate();
    panel.Children.Add(presenter);
}

// this doesn't seem to help: panel.UpdateLayout();
panel.Measure(new Size(this.Width, Double.PositiveInfinity));
panel.Arrange(new Rect(panel.DesiredSize));

return panel.ActualHeight;

The data template definitely makes use of the shared size groups:

<DataTemplate ...>
    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="Auto" SharedSizeGroup="MedCol0" />
            <ColumnDefinition Width="Auto" SharedSizeGroup="MedCol1" />
            <ColumnDefinition Width="Auto" SharedSizeGroup="MedCol2" />
            <ColumnDefinition Width="Auto" SharedSizeGroup="MedCol3" />
            <ColumnDefinition Width="*" />
    </Grid.ColumnDefinitions>

    <TextBlock Grid.Column="0" Text="{Binding Name}" />
    <TextBlock Grid.Column="1" Text="{Binding StartDate}" />
    ...
    <TextBlock Grid.Column="4" Text="{Binding Comments}" TextWrapping="Wrap" />
</DataTemplate>

And when it's presented on the UI via XAML, it works fine too:

<ItemsControl Grid.IsSharedSizeScope="True" ItemsSource="..." ItemTemplate="..." />

It simply doesn't work in the code-behind when I build a panel by hand to evaluate ActualHeight before anything gets rendered to the screen.

For whatever reason, when I set a breakpoint and watch the ActualWidth of each grid column, they vary row by row. I don't know why the shared size scope doesn't work in this code. Any ideas? Do I need to invoke some other WPF method for updating layout?

0

There are 0 answers