简体   繁体   English

寻找WPF Grid ColumnSpan行为的解释

[英]Looking for explanation for WPF Grid ColumnSpan behavior

I asked a question at http://social.msdn.microsoft.com/Forums/en-US/wpf/thread/5c7f5cdf-4351-4969-990f-29ce9ec84b87/ , but still lack a good explanation for a strange behavior. 我在http://social.msdn.microsoft.com/Forums/en-US/wpf/thread/5c7f5cdf-4351-4969-990f-29ce9ec84b87/上提出了一个问题,但对一个奇怪的行为仍然缺乏一个很好的解释。

Running the following XAML shows that the TextBlock in column 0 is width greater than 100 even though the column is set to width 100. I think that the strangeness may have something to do with it being wrapped in a ScrollViewer, but I don't know why. 运行以下XAML显示第0列中的TextBlock宽度大于100,即使该列设置为宽度100.我认为奇怪的可能与它被包装在ScrollViewer中有关,但我不知道为什么。 If I set a MaxWidth on the columns, it works fine, but setting Width does not. 如果我在列上设置MaxWidth,它可以正常工作,但设置Width不会。

  1. Why is the width of column 0 not being honored? 为什么列0的宽度不被尊重?
  2. Why does the column sizing behave differently when you remove the scroll viewer? 删除滚动查看器时,为什么列大小调整的行为会有所不同?

I appreciate any explanation! 我感谢任何解释! This is a real puzzle to me. 这对我来说真是一个难题。

<Window x:Class="WpfApplication2.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="MainWindow" Width="300">
    <ScrollViewer HorizontalScrollBarVisibility="Auto" >
        <Grid>
            <Grid.RowDefinitions>
                <RowDefinition Height="Auto" />
                <RowDefinition Height="Auto" />
            </Grid.RowDefinitions>
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="100" />
                <ColumnDefinition Width="100" />
                <ColumnDefinition />
            </Grid.ColumnDefinitions>
            <TextBlock x:Name="textBlock" Text="{Binding ElementName=textBlock, Path=ActualWidth}" />
            <TextBlock Text="column 1" Grid.Column="1" />
            <TextBlock Grid.Row="1" Grid.ColumnSpan="3" Text="text here that is wider than the first two columns combined" />
        </Grid>
    </ScrollViewer>
</Window>

This is a very good question and tests the limits of our intuition. 这是一个非常好的问题,并测试了我们直觉的极限。 It reveals the implementation details of the Grid's layout logic. 它揭示了Grid的布局逻辑的实现细节。

The width of 100 is not being honored because: 100的宽度没有被尊重,因为:

  1. There is nothing in the third column that causes the grid to give it width. 第三列中没有任何内容可以使网格给它宽度。
  2. The long text in the second row is wider than can fit in the first two columns. 第二行中的长文本比前两列中的长文本宽。
  3. When the width of the Grid is not constrained or set by its parent its layout logic evidently stretches the first column instead of the last column. 当Grid的宽度不受其父级约束或设置时,其布局逻辑显然会拉伸第一列而不是最后一列。

By putting a MaxWidth on the first column, you are constraining the Grid's layout logic, so it moves on to the second column and stretches it. 通过在第一列上放置MaxWidth,您将约束Grid的布局逻辑,因此它将移动到第二列并对其进行拉伸。 You'll note it will be wider than 100 in that scenario. 你会注意到在这种情况下它将超过100。

However, as soon as the Grid's width is set to a specific value or is constrained by its parent (eg when no ScrollViewer in the Window), the Grid's width has a specific value, and the third column gets a width set even though it is empty. 但是,只要Grid的宽度设置为特定值或受其父级约束(例如,窗口中没有ScrollViewer),Grid的宽度就会有一个特定的值,而第三列的宽度设置为即使它是空。 Now the Grid's auto-size code is deactivated, and it no longer stretches any of your columns to try to squeeze in that text. 现在Grid的自动调整大小代码已停用,它不再延伸任何列以尝试挤入该文本。 You can see this by putting a specific width on the Grid, even though it is still in the ScrollViewer. 您可以通过在Grid上放置特定宽度来查看此内容,即使它仍在ScrollViewer中。

Edit: Now that I read the answer of the MSDN support in your original thread, I believe it is correct, meaning this is probably the result of the implementation of the attached property and not the grid itself. 编辑:现在我在原始线程中阅读了MSDN支持的答案,我认为这是正确的,这意味着这可能是附加属性的实现而不是网格本身的结果。 However, the principle is the same, and hopefully my explanation is clear enough to make sense of the subtlety here. 然而,原则是一样的,希望我的解释足够清楚,以理解这里的微妙之处。

Short Answer: 简答:
Its because of the combination of: 它因为以下组合:
1. Presence of ScrollViewer which allows grid (if it wishes) to take any desired size. 1. ScrollViewer的存在,允许网格(如果愿意)采取任何所需的大小。
2. The grid not having explicit width. 2.网格没有明确的宽度。
3. A column (Column 2) whose width has not been specified, which sets it to 1*, leaving its final size dependant on size of grid and other columns. 3.未指定宽度的列(第2列),将其设置为1 *,其最终大小取决于网格和其他列的大小。
4. TextBlock which has colspan over three columns. 4.具有三列colspan的TextBlock。

If you: 如果你:
1. Remove the scrollviewer, the grid is allowed to grow only till the client area of window (which comes to be about 278 in your example), and the long textblock has to fit within this width otherwise its trimmed. 1.删​​除滚动查看器,网格只允许生长到窗口的客户区域(在您的示例中大约为278),并且长文本块必须适合此宽度,否则将其修剪。
2. Set explicit width of Grid, which again trims textblock to fit. 2.设置Grid的显式宽度,再次修剪文本块以适应。
3. Set explicit width of Column 2, which provides a fixed width to grid (100+100+width_of_col2), which again trims textblock to fit. 3.设置第2列的显式宽度,它为网格提供固定宽度(100 + 100 + width_of_col2),再次修剪文本块以适应。
4. Remove the colspan, the columns which do not contain it and have fixed width defined, will take that width. 4.删除colspan,不包含它的列和定义的固定宽度将采用该宽度。

Here's what's happening: 这是发生了什么:
This is crude and not exact explanation of the measure and arrange passes , however, it should give a fair idea. 这是粗略的,并没有对措施和安排通行证的确切解释,但是,它应该给出一个公平的想法。

To start with col0 is happy with 100, col1 with 100 and col2 with 0. Based on this grid's size would be 100+100+0=200. 首先col0为100,col1为100,col2为0.基于此网格的大小为100 + 100 + 0 = 200。 When Grid requests its children (textblocks) to be measured, it sees that first two textblocks fit within the width of their columns. 当Grid要求测量其子(文本块)时,它会看到前两个文本块适合其列的宽度。 However, the third textblock needs 288. Since, grid isn't having any width defined and its within a scrollviewer, it can increase its size if one of its child needs it. 但是,第三个文本块需要288.因为,网格没有定义任何宽度并且在滚动查看器中,如果其中一个孩子需要它,它可以增加其大小。 The Grid has now to increase its size from 200 to 288 (ie by 88). Grid现在已将其规模从200增加到288(即88)。 This means each column to which that textblock spans (all three of them) will expand by 88/3~=29 pixels. 这意味着该文本块跨越的所有列(所有三个)将扩展88 / 3~ = 29像素。 This makes col0=100+29=129, col1=100+29=129, col2=0+29. 这使得col0 = 100 + 29 = 129,col1 = 100 + 29 = 129,col2 = 0 + 29。

Try this: 试试这个:
Include a rectangle, put it in col2 and set width of rectangle to 20. 包含一个矩形,将其放在col2中并将矩形宽度设置为20。

This is what's happening: 这就是发生的事情:
To start with col0 and col1 are happy with 100 each as their individual textblocks need less than that. 从col0和col1开始,每个100都满意,因为它们的单个文本块需要少于它。 col2 is happy with 20 as rectangle in it needs that. col2很满意20,因为它需要矩形。 Based on this grid's width would be 100+100+20=220. 基于此网格的宽度将为100 + 100 + 20 = 220。 However, because of the columnspanning textblock the Grid has to increase its size from 220 to 288 (ie by 68). 但是,由于列跨越文本块,Grid必须将其大小从220增加到288(即68)。 This means each column to which that textblock spans (all three of them) will expand by 68/3~=23 pixels. 这意味着该文本块跨越的所有列(所有三个)将扩展68 / 3~ = 23像素。 This makes col0=100+23=123, col1=100+23=123, col2=20+23=43. 这使得col0 = 100 + 23 = 123,col1 = 100 + 23 = 123,col2 = 20 + 23 = 43。

HTH. HTH。

Here is another example that shows the problem using a Canvas instead of a ScrollViewer : 这是另一个使用Canvas而不是ScrollViewer显示问题的示例:

<Canvas>
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="Auto"/>
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="100"/>
            <ColumnDefinition Width="100"/>
            <ColumnDefinition/>
        </Grid.ColumnDefinitions>
        <TextBlock Grid.Column="0" x:Name="textBlock1" Text="{Binding ElementName=textBlock1, Path=ActualWidth}"/>
        <TextBlock Grid.Column="1" x:Name="textBlock2" Text="{Binding ElementName=textBlock2, Path=ActualWidth}"/>
        <TextBlock Grid.Row="1" Grid.ColumnSpan="3" Width="300"/>
    </Grid>
</Canvas>

This example shows that when given unlimited space, the first two columns are incorrectly expanded by 33%. 此示例显示,当给定无限空间时,前两列错误地扩展了33%。 I do not have working reference source to debug this right now because SP1 broke .NET4 reference source but frankly pinpointing this to the line in the source file is not going to help you so let's not go that route. 我现在没有工作参考源来调试这个,因为SP1破坏了.NET4参考源,但是坦率地将它指向源文件中的行并不会对你有帮助,所以让我们不要去那条路。

Instead, we'll agree that this is definitely a bug and we can prove that it's a bug by setting Grid.MaxWidth to progressively larger values and the widths of two columns remain both at 100 no matter how large it gets. 相反,我们同意这绝对是一个错误,我们可以通过将Grid.MaxWidth设置为逐渐变大的值来证明这是一个错误,并且无论它有多大,两列的宽度都保持在100。 But if you leave Grid.MaxWidth unset and place the Grid inside of a Canvas then the value during measure will be double.PositiveInfinity and this value with produce column widths of 133. As a result we can speculate that some how the special case of a size constraint of positive infinity is not handled correctly during the column sizing calculations. 但是如果你不设置Grid.MaxWidth并将Grid放在Canvas那么measure中的值将是double.PositiveInfinity并且这个值的生成列宽为133.因此我们可以推测一些特殊情况如何在列大小计算期间,无法正确处理正无穷大的大小约束。

Luckily, that same experiment provides a simple workaround: simply supply an absurdly large value for Grid.MaxWidth when the Grid is used inside another control that allows it unlimited space, such as a ScrollViewer or a Canvas . 幸运的是,同样的实验提供了一个简单的解决方法:当Grid在另一个允许无限空间的控件中使用时,只需为Grid.MaxWidth提供一个非常大的值,例如ScrollViewerCanvas I recommend something like: 我建议像:

<Grid MaxWidth="1000000">

This approach avoids the bug by preventing the size constraint from having the probematic value of positive infinity, while practically achieving the same effect. 这种方法通过防止大小约束具有正无穷大的探测值来避免该错误,同时实际上实现相同的效果。

But this: 但是这个:

<Grid MaxWidth="{x:Static sys:Double.PositiveInfinity}">

will trigger the bug. 会触发错误。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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