当您的子元素始终包含在单个网格单元格中时(即没有列/行跨越),使用WPF网格控件很容易。固定宽度列保持所请求的固定宽度,自动列的大小确实与列中最宽的单元格一样宽。星列根据其相对星值共享任何剩余空间。一切都很简单。
但是一旦你有一个跨越两列或更多列的单元格,列的宽度变得更加复杂,并且确实看起来很反直觉。这是我的意思的一个简单例子。我们可以定义两列,第一列为auto,第二列为30像素。
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="30"/>
</Grid.ColumnDefinitions>
现在我们定义一个跨越两列的按钮,恰好以80像素宽度进行测量。 (在我的机器上使用我的字体和主题设置等...)
<Button Grid.ColumnSpan="2" Content="QWERTYUIOP"/>
我们需要在两个生成列上分配按钮的80像素宽度。鉴于第二列固定为30,我预计将为该列分配30,剩余的50将转到第一列。因为第一列是自动的,所以看起来很明显。
但不是。如果你在实践中尝试这个,你会发现第一列是0像素而第二列已经变成完整的80.即使第二列被定义为固定,因此不应该变得更大,它会拉伸到整个宽度的按钮。也许我在这里遗漏了一些东西,但这对我来说似乎不合逻辑。
所以对我的实际问题。是否对Grid控件用于执行此计算的逻辑有完整描述,以便我可以完全理解它是如何工作的?我搜索过MSDN和Google,但没有找到任何描述生成元素如何影响列宽的内容。
答案 0 :(得分:5)
老实说,当我读到这篇文章时,我不相信你,所以我不得不自己去测试,而且你的确是正确的。我不认为你有任何运气找到规则,因为进一步的调查让我相信它是WPF网格中的一个错误。我进行了一些测试,看看我是否可以弄清楚这种行为,但如果你只是想知道最后的结论,请随意翻阅以下的dia骂。
很抱歉,如果结果不清楚,那就是我把它们写成工作的方式。前三个数字是我为每列放入的大小值,其余是结果大小。
测试1:
<Grid Height="300" Width="300">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="..."/>
<ColumnDefinition Width="..."/>
<ColumnDefinition Width="..."/>
</Grid.ColumnDefinitions>
<Button Grid.ColumnSpan="2" Content="QWERTYUIOP"/>
</Grid>
Grid 300 X 300托管一个80像素宽的控制器。网格有三列,控件跨越列0和1:
30 , auto, * - column 0 - 80, column 1 - 0, column 2 - 220
auto, auto, * - column 0 - 40, column 1 - 40, column 2 - 220
auto, 30 , * - column 0 - 0, column 1 - 80, column 2 - 220
* , 30 , * - column 0 - 135, column 1 - 30, column 2 - 135
* , 30 , 26* - column 0 - 10, column 1 - 30, column 2 - 260
* , auto, * - column 0 - 150, column 1 - 0, column 2 - 150
* , auto, 30* - column 0 - 10, column 1 - 0, column 2 - 290
30 , 30 , * - column 0 - 30, column 1 - 30, column 2 - 240
* , * , 28* - column 0 - 10, column 1 - 10, column 2 - 280
因此,我可以提出一些规则:
测试2:
<Grid ShowGridLines="True" Height="300" Width="300">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="..."/>
<ColumnDefinition Width="..."/>
<ColumnDefinition Width="..."/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Button Grid.ColumnSpan="2" Content="QWERTYUIOP"/>
<Button Grid.Row="1" Grid.Column="1" Content="QWERTYUIOP"/>
</Grid>
Grid 300 X 300,其中3列托管一个控件80像素宽,第0行和第2行第0行,第二个控件仅80行像素,第1行第1列
30 , auto, * - column 0 - 30, column 1 - 80, column 2 - 190
auto, auto, * - column 0 - 0, column 1 - 80, column 2 - 220
auto, 30 , * - column 0 - 0, column 1 - 80, column 2 - 220 (*)
* , 30 , * - column 0 - 135, column 1 - 30, column 2 - 135
* , 30 , 26* - column 0 - 10, column 1 - 30, column 2 - 260
* , auto, * - column 0 - 110, column 1 - 80, column 2 - 110
* , auto, 30* - column 0 - 7, column 1 - 80, column 2 - 213
30 , 30 , * - column 0 - 30, column 1 - 30, column 2 - 240
* , * , 28* - column 0 - 10, column 1 - 10, column 2 - 280
(*)这不完全是这样。第1列设置为80,但仅绘制部分非跨越元素。我使用按钮作为我的元素,非跨越按钮的chrome填充了80像素宽的第一列,但文本被修剪为30像素的大小。基本上它完全搞砸了。
从这个测试我可以再添加两个规则:
所以,我想我们可以将这些规则结合成一个总体理念:
如果元素跨越多个列并且这些列中的至少一个(但不是全部)是自动调整大小,则必须存在另一个不跨越的列以提供自动调整大小的列的大小。否则,这种行为最多是出乎意料的,最糟糕的是腐败。
随意提出一个微软的错误,但由于现在这是网格控件的定义行为,我想我们在WPF的生命周期中一直坚持它。
答案 1 :(得分:0)
这是怎么做的:
如果requestedSize(childelement.DesiredSize)符合范围(span)的首选大小。 RequestedSize根据以下逻辑分发:
如果requestedSize大于首选大小,但符合范围的最大大小。 RequestedSize根据以下逻辑分发:
对于所有非自动定义,请求的大小在它们之间平均分配;不超过每个的最大值。
然后从上面的步骤中剩余的大小平均分配在自动定义之间。
如果requestedSize大于范围的最大大小。 RequestedSize按以下方式在所有定义之间平均分配:
如果equi-size小于maxSizes的最大值。
在这种情况下,大小的分布方式使得较小的定义比较大的定义增长得快。
所有定义都将获得equalSize作为其最小尺寸。
答案 2 :(得分:-1)
我不知道互联网上是否有完整的描述..
我知道,自动意味着它会要求孩子控制他们希望的大小。星号(*)表示它将占用它剩下的所有空间......
编辑:即时更新.. 宽度(ColumnDefinition)和高度(RowDefinition)是GridLength结构: