9

我在http://social.msdn.microsoft.com/Forums/en-US/wpf/thread/5c7f5cdf-4351-4969-990f-29ce9ec84b87/上问了一个问题,但对于奇怪的行为仍然缺乏很好的解释。

运行以下 XAML 显示第 0 列中的 TextBlock 的宽度大于 100,即使该列设置为宽度 100。我认为奇怪可能与它被包装在 ScrollViewer 中有关,但我不知道为什么。如果我在列上设置 MaxWidth,它可以正常工作,但设置 Width 不会。

  1. 为什么不遵守第 0 列的宽度?
  2. 为什么删除滚动查看器时列大小的行为会有所不同?

我很感激任何解释!这对我来说是一个真正的难题。

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

4 回答 4

6

这是一个很好的问题,考验着我们直觉的极限。它揭示了 Grid 布局逻辑的实现细节。

100 的宽度没有得到尊重,因为:

  1. 第三列中没有任何内容导致网格为其提供宽度。
  2. 第二行中的长文本比前两列更宽。
  3. 当 Grid 的宽度不受其父级约束或设置时,其布局逻辑显然会拉伸第一列而不是最后一列。

通过将 MaxWidth 放在第一列,您限制了 Grid 的布局逻辑,因此它移动到第二列并拉伸它。您会注意到在这种情况下它会比 100 更宽。

但是,一旦 Grid 的宽度设置为特定值或受其父级约束(例如,当 Window 中没有 ScrollViewer 时),Grid 的宽度具有特定值,并且第三列即使它是空的。现在,网格的自动大小代码已停用,它不再拉伸您的任何列以尝试挤入该文本。您可以通过在 Grid 上放置特定宽度来查看这一点,即使它仍在 ScrollViewer 中。

编辑:现在我在您的原始线程中阅读了 MSDN 支持的答案,我相信它是正确的,这意味着这可能是附加属性实现的结果,而不是网格本身。然而,原理是一样的,希望我的解释足够清楚,可以理解这里的微妙之处。

于 2011-04-15T17:50:49.443 回答
3

简短的回答:
这是因为以下组合:
1. ScrollViewer 的存在,它允许网格(如果它愿意)采用任何所需的大小。
2. 网格没有明确的宽度。
3. 未指定宽度的列(第 2 列),将其设置为 1*,其最终大小取决于网格和其他列的大小。
4. TextBlock,其 colspan 超过三列。

如果您:
1. 移除滚动查看器,网格只能增长到窗口的客户区域(在您的示例中约为 278),并且长文本块必须适合此宽度,否则会被修剪。
2.设置网格的显式宽度,再次修剪文本块以适应。
3. 设置第 2 列的显式宽度,为网格提供固定宽度 (100+100+width_of_col2),再次修剪文本块以适应。
4.删除colspan,不包含它并且定义了固定宽度的列将采用该宽度。

这是正在发生的事情:
这是对措施和安排通行证的粗略而不是准确的解释,但是,它应该给出一个公平的想法。

从 col0 开始对 100 表示满意,col1 表示为 100,col2 表示为 0。基于此网格的大小将是 100+100+0=200。当 Grid 请求测量其子项(文本块)时,它会看到前两个文本块适合其列的宽度。但是,第三个文本块需要 288。由于网格没有定义任何宽度并且它位于滚动查看器中,因此如果其中一个子需要它,它可以增加它的大小。网格现在必须将其大小从 200 增加到 288(即增加 88)。这意味着该文本块跨越的每一列(全部三个)将扩展 88/3~=29 像素。这使得 col0=100+29=129, col1=100+29=129, col2=0+29。

试试这个:
包括一个矩形,把它放在 col2 中,并将矩形的宽度设置为 20。

这就是发生的事情:
从 col0 开始,col1 对每个 100 感到满意,因为它们各自的文本块需要的更少。col2 对 20 作为矩形感到满意,因为它需要它。基于这个网格的宽度将是 100+100+20=220。但是,由于跨列文本块,网格必须将其大小从 220 增加到 288(即增加 68)。这意味着该文本块跨越的每一列(全部三个)将扩展 68/3~=23 像素。这使得 col0=100+23=123, col1=100+23=123, col2=20+23=43。

HTH。

于 2011-04-15T18:23:37.233 回答
2

Canvas这是另一个使用 a而不是 a显示问题的示例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>

此示例显示,当给定无限空间时,前两列错误地扩展了 33%。我现在没有可用的参考源来调试它,因为 SP1 破坏了 .NET4 参考源,但坦率地说,将其精确定位到源文件中的行对您没有帮助,所以我们不要走那条路。

相反,我们会同意这绝对是一个错误,我们可以通过设置逐渐变大的值来证明它是一个错误,Grid.MaxWidth并且无论它变得多大,两列的宽度都保持在 100。但是,如果您Grid.MaxWidth保持未设置并放置在Grida 的内部,Canvas那么测量期间的值将是double.PositiveInfinity并且该值产生的列宽为 133。因此,我们可以推测一些如何处理正无穷大的大小约束的特殊情况在列大小计算期间正确。

Grid.MaxWidth幸运的是,同一个实验提供了一个简单的解决方法:当Grid在另一个允许无限空间的控件(例如 aScrollViewer或 a )中使用 时,只需提供一个大得离谱的值Canvas。我推荐类似的东西:

<Grid MaxWidth="1000000">

这种方法通过防止大小约束具有正无穷大的探测值来避免错误,同时实际上实现了相同的效果。

但是这个:

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

将触发错误。

于 2011-04-27T05:07:42.350 回答
0

我将此问题报告为错误:

https://connect.microsoft.com/VisualStudio/feedback/details/665448/wpf-grids-columns-width-property-not-honored-when-columnspan-row-forces-grid-to-grow

如果您同意这是一个错误,请在该链接上投票。

于 2011-04-28T14:03:18.160 回答