【问题标题】:Why is this extra space appearing in a Grid?为什么这个额外的空间会出现在网格中?
【发布时间】:2013-04-25 15:56:39
【问题描述】:

我在查看this question 并发现了一些非常奇怪的东西:在涉及Grid.RowSpan 的某些情况下,似乎行的高度计算不正确。

这是我正在测试的Grid 的简单绘图:

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

这里有一些演示该问题的 Grid 示例代码:

<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>

最终结果是第 3 行(单元格 #2 和 #3)的高度有很多额外的空间:

如果我将第一个和第三个单元格的 Grid.RowSpan 调整 +/- 1,并将第二个和第四个单元格的 Grid.Row 调整 +/- 1 以考虑额外的行,我会得到这个(正确) 结果:

如果我从单元格 #3 中删除足够多的元素以便它可以在单个行中呈现,我也会得到正确的结果,如下所示:

奇怪的是,删除一些对象只会应用一些额外的空间

我一直在搞乱 #1 和 #3 单元格中的元素数量以及行数,但我似乎无法找到解释这种行为的结论性模式。

在渲染此 Grid 时 WPF 在幕后究竟做了什么以导致在单元格 #3 上出现Grid.RowSpan 时出现额外空间?

【问题讨论】:

  • 我想说的是因为网格的测量方式不同,但我对所有堆栈面板都进行了尝试,但它的大小仍然错误。
  • “自动”行高太多。 Grid 控件在处理跨行和跨列方面做得很好,但是当所有行高都设置为“自动”时,它就像求解一个包含太多未知数的方程。将前 2 行中的 1 行或全部限制到固定高度有很大帮助。
  • @Stewbob 我也测试过将最后一行留在Height="*",但这并没有什么不同。问题在于确定使用RowSpan 的单元格的高度,与Grid 如何分配额外的垂直空间无关。我已经更新了我的代码示例以包含一个* 大小的行,以帮助说明这一点:)
  • 不是“*”,即“剩余”或“比例”空间,而是前两行中1行的实际固定值;正在跨越的那些。如果您将 RowDefinitions 中第一行的高度设置为固定值,例如“30”,它会正确调整跨度的大小。
  • @Stewbob 6 auto 在一个简单的布局上有太多的未知数。

标签: wpf grid


【解决方案1】:

我以前也遇到过这种情况,如my question here 中关于额外空间appearing in a ListView

根据我从微软员工那里得到的回复:

该错误涉及 VSP 测量算法中的一个步骤,该算法会记住有史以来发现的最大尺寸,并强制所有未来的测量调用报告至少一样大的尺寸。在您的情况下,VSP 最初是在触发任何触发器之前测量的,因此它计算大小就像一切都是可见的。当触发器触发并折叠按钮时,测量算法会计算正确的(小)尺寸,但随后会强制结果再次变大。

您的网格的行为与我的虚拟化堆栈面板的行为相似:RowDefinition 的 Measure 调用发生了一些事情,这迫使它记住并始终报告更大的大小,即使稍后在线小一点会更好。

简而言之,您可能在 WPF 中发现了一个错误,因为有无数的解决方法(将定义的总行数与所需的总行数相匹配,重新排列您的网格,无论其他什么......)可能永远不会引起注意。您只能通过打开 Microsoft Connect 错误并等待他们的回复来确认或反驳这一点。

【讨论】:

  • 您链接的那篇文章非常有趣,我怀疑您认为它是 Measure 调用中的错误是正确的。我希望您不介意,但我将稍微编辑您的答案,以包括您链接帖子中的相对引用。我希望有人会发布一个答案,确切地解释幕后发生的事情以实现这一点,并由反射器或 MSDN 代码支持,但看起来这不会发生,所以我授予你赏金代表我认为你的答案是我最接近可靠答案的答案。
  • Rachel 我认为你刚刚证明了一个好编辑的价值。兰登书屋,注意!
【解决方案2】:

对于 .NET 为何您的第三行出错,我没有完整的答案。
但我认为你要求它做的事情是不合逻辑的,因为没有理由让 0,0 跨越两行。
共享行时,它们的长度可能不相等,并且 WPF 必须将长度添加到较短的部分。
在您的情况下,由于您在共享行中有共享行,因此 WPF 必须应用一些权重并且不能正确执行。
如果您不跨越 0 0 则与第 0 行第 0 列和第 1 行第 0 列共享额外的额外空间,这(对我而言)是正确答案。

<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>

【讨论】:

  • 是的,我知道这样的代码是不合逻辑的,并且有一些简单的方法可以避免这种行为,例如删除不需要和未定义的第二行 (Grid.Row="1"),但我很好奇WPF 在幕后做了什么来决定首先以这种方式渲染,并且只使用特定的 RowSpan。我怀疑你是对的,WPF 在测量未定义的行时错误地应用了一些权重,因为元素的数量会影响绘制多少额外空间。我猜我需要拔出反光板才能得到明确的答案......
  • 我怀疑它的权重错误(但我看不出有什么正当的理由让它变重)。在您看到似乎正确的权重的地方,我怀疑增量为 0,而权重为 0 错误,您看不到错误的答案。
【解决方案3】:

正如 Rob 所说,这可能是 WPF 测量调用中的一个错误。所以我不知道你的答案。但是为了探索 WPF 应用程序的内部工作原理,我使用了Snoop。这是一个很棒的工具,类似于显示 HTML 元素的浏览器工具,snoop 向您展示您的 WPF 表单的布局、嵌套元素、元素的属性等。它在试图找出布局问题时帮助了我很多。我想我会提到。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-09-29
    • 1970-01-01
    • 1970-01-01
    • 2014-06-22
    • 2011-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-01-13
    相关资源
    最近更新 更多