0
votes

I have a 'pile' of expanders on top of each other, which can be opened/closed independently.

All but one have a fixed height (when expanded). The other has a MinHeight, but I would like it to stretch to fill the remaining available height. If the combined heights of the expanders is greater than the available height, then scrollbars appear.

I've got that far using a Grid, with one expander per grid, and the row Height set to * for the stretching expander, and Auto for the others.

This works fine except in one case: if the stretchy expander is collapsed, and the combined height of the other expanders is less than the available height, then the stretching expander fills the remaining space anyway, just with it's content collapsed so I get a big blob of background colour.

I've also tried a StackPanel, or nested Grids, but haven't managed to resolve that problem without creating others.

Any ideas?

(Paste this into a Window)

<ScrollViewer>
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="*" MinHeight="23"/>
            <RowDefinition Height="Auto"/>
        </Grid.RowDefinitions>
        <Expander IsExpanded="False" Grid.Row="0" Header="Fixed">
            <Border Background="Red" Height="200" />
        </Expander>
        <Expander IsExpanded="False" Grid.Row="1" Header="Stretchy">
            <Border Background="Blue" />
        </Expander>
        <Expander IsExpanded="False" Grid.Row="2" Header="Fixed">
            <Border Background="Green" Height="300" />
        </Expander>
    </Grid>
</ScrollViewer>
1
Could you insert your xaml? It's clear more or less, but i wanna see it :)sac1
@sac1 Your wish is my command...Benjol

1 Answers

1
votes

The Expander takes by default all available space. It does this by setting VerticalAlignment and HorizontalAlignment to Stretch.

To solve your problem set VerticalAlignment to Top. Then the Expander takes only the space it needs.

The XAML would look like this:

<Grid>
    <Grid.RowDefinitions>
        <RowDefinition Height="auto" />
        <RowDefinition Height="auto" />
        <RowDefinition Height="*" />
    </Grid.RowDefinitions>

    <Expander Grid.Row="0" Background="Green">
        <Button Height="50">test</Button>
    </Expander>
    <Expander Grid.Row="1" Background="Red">
        <Button Height="50">test</Button>
    </Expander>
    <Expander Grid.Row="2" Background="Blue" VerticalAlignment="Top">
        <Button Height="50">test</Button>
    </Expander>
</Grid>

EDIT:

You should bind the Height of the second row to IsExpanded of the stretchy expander. If it is expanded, set it to *, if not, set it to auto. You can do this by using a ValueConverter.

EDIT 2:

As promised the markup and the value converter that solve your problem:

<ScrollViewer>
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="{Binding ElementName=Stretchy, Path=IsExpanded, Converter={StaticResource converter}}" MinHeight="23" />
            <RowDefinition Height="Auto"/>
        </Grid.RowDefinitions>
        <Expander IsExpanded="False" Grid.Row="0" Header="Fixed">
            <Border Background="Red" Height="200" />
        </Expander>
        <Expander x:Name="Stretchy" IsExpanded="False" Grid.Row="1" Header="Stretchy" VerticalAlignment="Stretch" MinHeight="100">
            <Border Background="Blue" />
        </Expander>
        <Expander IsExpanded="False" Grid.Row="2" Header="Fixed">
            <Border Background="Green" Height="300" />
        </Expander>
    </Grid>
</ScrollViewer>

ValueConverter:

public class BoolToHeightConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        bool? v = value as bool?;
        if (v == false)
            return new GridLength(1, GridUnitType.Auto);
        else
            return new GridLength(1, GridUnitType.Star);
    }

    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}