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?