简体   繁体   中英

Why is this extra space appearing in a Grid?

I was looking at this question and discovered something very weird: it appears that the height of a row is incorrectly calculated in some cases involving Grid.RowSpan .

Here's an simple drawing of the Grid I'm testing with:

---------------
|   1   |     |
--------|  3  |
|   2   |     |
---------------
|      4      |
---------------

And here's some sample code for this Grid that demonstrates the problem:

<Grid ShowGridLines="True">
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="*"/>
        <ColumnDefinition Width="*"/>
    </Grid.ColumnDefinitions>
    <Grid.RowDefinitions>
        <RowDefinition Height="Auto"/>
        <RowDefinition Height="Auto"/>
        <RowDefinition Height="Auto"/>
        <RowDefinition Height="Auto"/>
        <RowDefinition Height="Auto"/>
        <RowDefinition Height="Auto"/>
        <RowDefinition Height="*"/>
    </Grid.RowDefinitions>

    <StackPanel Grid.Column="0" Grid.Row="0" Grid.RowSpan="2" Background="Red">
        <Label Content="CELL 1 A"/>
        <Label Content="CELL 1 B"/>
        <Label Content="CELL 1 C"/>
    </StackPanel>

    <Grid Grid.Column="0" Grid.Row="2" Background="CornflowerBlue">
        <Label Content="CELL 2 D"/>
    </Grid>

    <StackPanel Grid.Column="1" Grid.Row="0" Grid.RowSpan="3" Background="Yellow">
        <Label Content="CELL 3 A"/>
        <Label Content="CELL 3 B"/>
        <Label Content="CELL 3 C"/>
        <Label Content="CELL 3 D"/>
    </StackPanel>


    <Grid Grid.Column="0" Grid.Row="3" Grid.ColumnSpan="2" Background="Green">
        <Label Content="CELL 4"/>
    </Grid>
</Grid>

The end result is the height of the 3rd row (cell #2 and #3) has a lot of extra space in it:

在此输入图像描述

If I adjust the Grid.RowSpan of the 1st and 3rd cells by +/- 1, and adjust the Grid.Row for the 2nd and 4th by +/- 1 to account for the extra row, I get this (correct) result:

在此输入图像描述

I also get correct results if I remove enough elements from cell #3 so it can render in a single Row, like this:

在此输入图像描述

And strangely enough, removing some the objects results in only some of the extra space being applied

在此输入图像描述

I've been messing around with the number of elements in cells #1 and #3, and number of Rows, but I can't seem to figure out a conclusive pattern to explain this behavior.

What exactly is WPF doing behind the scenes when rendering this Grid to cause the extra space to appear when the Grid.RowSpan on cell #3?

I've run into this kind of condition before, as in my question here about extra space appearing in a ListView

Per a response I got from a Microsoft employee:

The bug involves a step in VSP's Measure algorithm that remembers the largest size ever discovered and forces all future Measure calls to report a size at least as large. In your case, the VSP is initially measured before any triggers have fired, so it computes the size as if everything were visible. When the triggers fire and collapse the buttons, the measure algorithm computes the correct (small) size, but then forces the result to be large again.

The behavior of your grid appears similar to the behavior of my Virtualizing Stack Panel: Something is going on with the RowDefinition 's Measure calls which force it to remember and always report a larger size, even though later on down the line a smaller one would be better.

In short, you probably found a bug in WPF, which, because there are myriad workarounds (match the total rows defined to the total needed, rearrange your grid, whatever else...) may never get attention. You can confirm or refute this only by opening a Microsoft Connect bug and waiting for their reply.

I don't have a full answer on why .NET does your 3rd row wrong.
But I contend what you are asking it to do is illogical as there is no reason to to have 0,0 span two rows.
When rows are shared they are not likely be equal length and WPF must add length to the shorter(s).
In you case since you have shared rows in the shared rows so WPF must apply some weighting and does not do that correctly.
If you don't span 0 0 then is shares the extra extra space with row 0 column 0 and row 1 column 0 equally which (to me) is the correct answer.

<Window x:Class="GridRowSizing.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525">
    <Window.Resources>
        <Style BasedOn="{StaticResource {x:Type Label}}" TargetType="Label">
            <Setter Property="BorderBrush" Value="Black"/>
            <Setter Property="BorderThickness" Value="1"/>
            <Setter Property="Margin" Value="3"/>
        </Style>
    </Window.Resources>
    <Grid ShowGridLines="True">
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="*"/>
            <ColumnDefinition Width="*"/>
        </Grid.ColumnDefinitions>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="Auto"/>
        </Grid.RowDefinitions>
        <StackPanel Grid.Column="0" Grid.Row="0" Background="Red">
            <Label Content="CELL 1 A"/>
            <Label Content="CELL 1 B"/>
            <Label Content="CELL 1 C" BorderBrush="Black" BorderThickness="2"/>
        </StackPanel>
        <StackPanel  Grid.Column="0" Grid.Row="1" Background="CornflowerBlue">
            <Label Content="CELL 2 D" BorderBrush="Black" BorderThickness="2"/>
            <Label Content="CELL 2 E" BorderBrush="Black" BorderThickness="2"/>
        </StackPanel>
        <StackPanel Grid.Column="1" Grid.Row="0" Grid.RowSpan="2" Background="Yellow">
            <Label Content="CELL 3 A"/>
            <Label Content="CELL 3 B"/>
            <Label Content="CELL 3 C"/>
            <Label Content="CELL 3 D" BorderBrush="Black" BorderThickness="2"/>
            <Label Content="CELL 3 E" BorderBrush="Black" BorderThickness="2"/>
            <Label Content="CELL 3 F" BorderBrush="Black" BorderThickness="2"/>
        </StackPanel>
        <StackPanel Grid.Column="0" Grid.Row="2" Grid.ColumnSpan="2" Background="Green">
            <Label Content="CELL 4"/>
        </StackPanel>
    </Grid>
</Window>

As Rob said, this is probably a bug in WPF measuring calls. So I don't know your answer. But to explore the inner workings of WPF apps, I use Snoop . It's an awesome tool, similar to the browser tools that show HTML elements, snoop shows you how your WPF form is laid out, nested elements, properties of elements, etc. It helps me a lot when trying to figure out layout issues. I thought I'd mention.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM