【发布时间】:2023-04-08 22:11:02
【问题描述】:
考虑以下 XAML:
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<Button Content="Button" HorizontalAlignment="Left"/>
<Grid Grid.Column="1">
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Button Content="B" Margin="5"/>
<Button Content="Button" Grid.Column="1" Margin="5"/>
</Grid>
</Grid>
在上面,除一个之外的所有ColumnDefinition 值都使用Width 的默认值,即"*",即“星号大小”。一个例外是包含嵌套Grid 控件的列,该控件设置为"Auto"。
我希望它的工作方式如下:
- 外层
Grid根据其内容的需要调整第二列的大小,然后将控件剩余的宽度分配给第一列。 - 内部
Grid将其可用空间均匀分配到两列。毕竟,它们都被设置为使用星号大小,并且星号大小应该将GridLength属性(在本例中为宽度)设置为可用空间的加权分布。这个内部Grid的最小布局大小(外部Grid需要计算其第二列的宽度)是均匀分布宽度、星型列的总和(即在这种情况下,两倍于内容最宽的列的宽度)。
但是,嵌套网格的列宽是根据每个按钮的计算最小尺寸设置的,两个星形大小的列之间没有明显的加权关系(为清楚起见,显示了网格线):
如果我没有外部网格,它会按预期工作,即只需使内部网格成为窗口中唯一的网格:
两列被强制为相同大小,然后当然左侧按钮被拉伸以适应其包含单元格的大小(这就是我想要的......最终目标是让这两个按钮拥有相同的宽度,网格列提供了实现这一点的布局)。
在这个特定示例中,我可以使用UniformGrid 作为解决方法,以强制均匀分布列宽。这就是我希望它实际的样子(UniformGrid 没有 ShowGridLines 属性,所以你只需要想象两个最右边的按钮之间的假想线):
但我真的很想更全面地了解如何实现这一点,以便在更复杂的场景中我能够在嵌套的Grid 控件中使用星号大小。
似乎不知何故,包含在另一个Grid 控件的单元格中正在改变为内部Grid 控件计算星号大小的方式(或完全阻止星号大小产生任何影响)。但是为什么会这样呢?我是否(再次)错过了一些将其解释为“设计使然”的行为的 WPF 的深奥布局规则?或者这只是框架中的一个错误?
更新:
我理解 Ben 的回答是指星号大小应该只分配剩余空间在每列的最小尺寸已被考虑在内。但这不是人们在其他情况下看到的。
例如,如果包含内部网格的列已明确调整大小,则对内部网格的列使用星号大小会导致列的大小均匀,正如我所期望的那样。
即这个 XAML:
<Grid ShowGridLines="True">
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<!--
<ColumnDefinition Width="Auto"/>
-->
<ColumnDefinition Width="60"/>
</Grid.ColumnDefinitions>
<Button Content="Button" HorizontalAlignment="Left"/>
<Grid Grid.Column="1" ShowGridLines="True">
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Button Content="B" Margin="5"/>
<Button Content="Button" Grid.Column="1" Margin="5"/>
</Grid>
</Grid>
产生这个输出:
换句话说,在最坏的情况下,我希望 WPF 首先计算内部网格的最小尺寸而不考虑星号大小(例如,如果短按钮占用 10 个像素,长按钮占用 70 个像素,那么总宽度将是 80),然后 still 均匀分布列宽(即在 10/70 示例中,每列将以 40 像素结束,截断较长的按钮,类似于上图) .
为什么星号有时应在列之间均匀分布宽度,有时则不能?
更新 #2:
这是一个简单的示例,它清楚而显着地展示了 WPF 如何根据是计算 Grid 宽度的人还是您来区别对待星号大小:
<Window x:Class="TestGridLayout2.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
SizeToContent="WidthAndHeight"
Title="MainWindow">
<Window.Resources>
<Style TargetType="Border">
<Setter Property="BorderBrush" Value="Black"/>
<Setter Property="BorderThickness" Value="1"/>
</Style>
<Style TargetType="TextBlock">
<Setter Property="FontSize" Value="24"/>
</Style>
</Window.Resources>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="3*"/>
</Grid.ColumnDefinitions>
<Border Grid.Column="0"/>
<Border Grid.Column="1"/>
<StackPanel>
<TextBlock Text="Some text -- one"/>
<TextBlock Text="Some text -- two"/>
<TextBlock Text="Some text -- three"/>
</StackPanel>
<StackPanel Grid.Column="1">
<TextBlock Text="one"/>
<TextBlock Text="two"/>
<TextBlock Text="three"/>
</StackPanel>
</Grid>
</Window>
当你运行程序时,你会看到:
WPF 忽略了星号大小,将每个列的宽度设置为最小。如果您只是单击窗口边框,就像调整窗口大小一样(您甚至不必实际将边框拖动到任何地方),Grid 布局就会重做,您会得到:
此时,应用了星号大小(正如我所期望的那样),并且根据 XAML 声明对列进行了比例调整。
【问题讨论】:
-
非常有趣!如果为嵌套网格显式设置
会怎样?亲切的问候, -
“最小布局大小”不是所有列中最大最小布局大小的两倍。它是每个列的最小布局大小的总和。星型大小不会影响最小值,它会影响额外空间的分布。
-
@AlexBell:明确设置宽度不会改变结果。 :(
-
@dubstylee:我认为当明确的
Width="*"不会改变行为时,这已被排除? -
@dubstylee:当你为两个内部列设置
Width="*"时,它们不能从外部网格继承Width="Auto",对吧?