0
votes

I'm using SizeToContent="WidthAndHeight" so that I can size a window to the size of the currently displayed controls. This works fine, however, I'm running into an issue when displaying and adding items to a listbox. When adding a great number of items to the listbox this will cause the window to extend below the edge of the monitor. I notice that without the SizeToContent="WidthAndHeight" I can easily get the Listbox to limit itself and use a scrollbar. However, this has the negative of displaying all the extra unused space that the listbox with take up before I have made it visible. I have added a small sample solution below to display this behaviour.

NOTE window does not need to be resizable. It just needs to be efficient on space and I would rather not use absolute values if possible.

Explaination of desired behaviour; user only sees the button, window has no unused space around the button. When the button is clicked the Listbox is now visible but has not extended beyond the screen (i.e. a scroll bar has been added) and the button beneath is visible.

...ResizeMode="CanMinimize" SizeToContent="WidthAndHeight">
<Grid>
    <Grid.RowDefinitions>
        <RowDefinition Height="Auto" />
        <RowDefinition Height="*"/>
        <RowDefinition Height="Auto" />
    </Grid.RowDefinitions>

    <Button Content="hello" Click="Button_Click"/>
    <ListView Name="lbx" Grid.Row="1" Visibility="Collapsed">
    </ListView>
    <Button Name="btn" Content="hello" Grid.Row="2" Visibility="Collapsed"/>

</Grid>

private void Button_Click(object sender, RoutedEventArgs e)
{
    btn.Visibility = Visibility.Visible;
    lbx.Visibility = Visibility.Visible;

    //Have tried various combinations of settings in code at runtime
    this.SizeToContent = SizeToContent.Width;
    this.Height = Double.NaN;

    for (int i = 0; i < 1000; i++)
    {
        lbx.Items.Add("Num:" + i);
    }

}

I've also tried this with a dockpanel instead of a Grid;

<Button Content="hello" Click="Button_Click" DockPanel.Dock="Top"/>
<Button Name="btn" Content="hello" DockPanel.Dock="Bottom" Visibility="Collapsed"/>
<ListView Name="lbx" Visibility="Collapsed">
</ListView>

Try swapping SizeToContent="WidthAndHeight" with SizeToContent="Width", the window starts up showing all the empty space that will later be used by the collapsed controls.

1
You may set the ListView's MaxHeight property. - Clemens

1 Answers

2
votes

You could set the MaxHeight of the window based on the actual height of the ListBox and the screen, e.g.:

private void Button_Click(object sender, RoutedEventArgs e)
{
    btn.Visibility = Visibility.Visible;
    lbx.Visibility = Visibility.Visible;

    for (int i = 0; i < 5; i++)
    {
        lbx.Items.Add("Num:" + i);
    }

    Dispatcher.Invoke(() =>
    {
        MaxHeight = Math.Min(SystemParameters.WorkArea.Height - Top, grid.ActualHeight);
    }, System.Windows.Threading.DispatcherPriority.Background);
}

This seems like a good option. One drawback is that with a small number of items it still introduces a scrollbar even when the listbox items should be able to fit.

Introduce an offset then:

private void Button_Click(object sender, RoutedEventArgs e)
{
    btn.Visibility = Visibility.Visible;
    lbx.Visibility = Visibility.Visible;

    for (int i = 0; i < 5; i++)
    {
        lbx.Items.Add("Num:" + i);
    }

    grid.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity));
    grid.Arrange(new Rect(new Size(grid.DesiredSize.Width, grid.DesiredSize.Height)));

    Height = Math.Min(SystemParameters.WorkArea.Height - Top, grid.ActualHeight + 40);
}