Kendall Frey
Kendall Frey

Reputation: 44374

WPF Grid sizing

This question is hard to describe succinctly, so bear with me.

Currently I have a Grid with two rows. The first row's height is Auto, and the second row's height is *, so when I resize the window, the second row grows and shrinks according to the window.

This is the basic layout:

<Window>
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto" />
            <RowDefinition Height="*" />
        </Grid.RowDefinitions>
        <Border>
            ...
        </Border>
        <Border Grid.Row="2">
            ...
        </Border>
    </Grid>
</Window>

Here is a poor sketch of the existing behaviour:

____    ____    ____
     ->      ->
____    ____    ____
                ____
        ____
____

I would like to add a sort of 'minimum height' to the second row, so that when I resize the window small enough, the second row stops shrinking, and the first row starts shrinking instead.

Desired behaviour:

____    ____    ____
     ->      -> ____
____    ____
                ____
        ____
____

Is there a simple way to get the minimum height for the second row, and force the first one to shrink?

More details:

When I set MinHeight on the second row, it just clips the grid when I resize it below that size.

The size of the controls in the first row are unknown at compile time, but known at runtime. If it is a necessary part of the solution, I could set the row's MaxHeight, but right now an Auto height is working.

The controls in the second row do not have an explicit size. They are allowed to be resized, but I'm trying to keep them from becoming smaller than the desired minimum height.

Upvotes: 6

Views: 7763

Answers (1)

Dylan Meador
Dylan Meador

Reputation: 2401

The size of the controls in the first row are unknown at compile time, but known at runtime. If it is a necessary part of the solution, I could set the row's MaxHeight, but right now an Auto height is working.

I think this is probably going to be the easiest solution. Bind the MaxHeight to the calculated value at runtime:

<Grid.RowDefinitions>
    <RowDefinition Height="*" MaxHeight="{Binding MyProperty}"/>
    <RowDefinition Height="*" MinHeight="100"/>
</Grid.RowDefinitions>

Edit: The previous solution is close, but not correct. Here is a way to achieve your desired result, however, not sure if it's the optimal approach:

<Grid ShowGridLines="True" Name="myGrid">
    <Grid.Resources>
        <local:RowHeightConverter x:Key="rowHeightConverter" />
    </Grid.Resources>
    <Grid.RowDefinitions>
        <RowDefinition Name="row1" MaxHeight="{Binding MyProperty}">
            <RowDefinition.Height>
                <MultiBinding Converter="{StaticResource rowHeightConverter}">
                    <Binding Path="ActualHeight" ElementName="row2" />
                    <Binding Path="ActualHeight" ElementName="myGrid" />
                    <Binding Path="MaxHeight" ElementName="row1" />
                </MultiBinding>
            </RowDefinition.Height>
        </RowDefinition>
        <RowDefinition Name="row2" Height="*" MinHeight="300"/>
    </Grid.RowDefinitions>
</Grid>

And your converter:

public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
    double row2Height = (double)values[0];
    double gridHeight = (double)values[1];
    double row1MaxHeight = (double)values[2];

    if (gridHeight - row2Height >= row1MaxHeight)
    {
        return gridHeight - row2Height;
    }

    return row1MaxHeight;
}

Upvotes: 7

Related Questions