如何使DockPanel填充可用空间

24

我正在尝试在 ItemsControl(ListBox) 中显示购物车的内容。为此,我创建了以下 DataTemplate

<DataTemplate x:Key="Templates.ShoppingCartProduct"
              DataType="{x:Type viewModel:ProductViewModel}">
    <DockPanel HorizontalAlignment="Stretch">
        <TextBlock DockPanel.Dock="Left"
                   Text="{Binding Path=Name}"
                   FontSize="10"
                   Foreground="Black" />
        <TextBlock DockPanel.Dock="Right"
                   Text="{Binding Path=Price, StringFormat=\{0:C\}}"
                   FontSize="10"
                   Foreground="Black" />
    </DockPanel>
</DataTemplate>

当商品在我的购物车中展示时,名称和价格的TextBlocks会并排显示,而右侧会有大量的空白。

想知道如何强制DockPanel填充由ListItem提供的所有可用空间的最佳方法是什么?

3个回答

34

DockPanelWidth 绑定到 ListBoxItemActualWidth

<DockPanel Width="{Binding ActualWidth, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ListBoxItem}}}">
...

另一个选项是重新定义ItemContainerStyle,使得ListBoxItem在水平方向上拉伸:

<ListBox.ItemContainerStyle>
    <Style TargetType="ListBoxItem">
        <Setter Property="HorizontalContentAlignment" Value="Stretch"/>
    </Style>
</ListBox.ItemContainerStyle>

我尝试使用那个绑定,但似乎导致 ListBoxItem 不断增大,在使用 Snoop 查看时,我发现 ListBoxItem 和 DockPanel 的宽度都超过了 300,000。 - Richard McGuire
3
好的,我明白了...你需要在DockPanel上设置LastChildFill="False",否则第二个TextBlock会被拉伸。 - Thomas Levesque
我最终找到了你的第二种方法并采用了那种方式。 - Richard McGuire
第二种方法可以奏效,如果你使用HorizontalContentAlignment而不是HorizontalAlignment。我编辑了回答。 - slfan
第一种方法在ListBox调整大小时无效。实际大小保持最大值不变。 - Benlitz
显示剩余3条评论

10

关于Dock面板的好处在于,它们已经填充了所有可用空间。默认情况下LastChildFill为true(但我在下面设置了它以使其更清晰),因此只需不在最后一个子元素上设置DockPanel属性,它就会填充可用空间。

<DockPanel HorizontalAlignment="Stretch" LastChildFill="true">
    <TextBlock DockPanel.Dock="Left"
               Text="{Binding Path=Name}"
               FontSize="10"
               Foreground="Black" />
    <TextBlock 
               Text="{Binding Path=Price, StringFormat=\{0:C\}}"
               FontSize="10"
               Foreground="Black" />
</DockPanel>

9

DockPanel是有害的。使用StackPanel/DockPanel组合进行复杂布局会导致“布局死角”。应该使用Grid:

<Grid>
  <TextBlock HorizontalAlignment="Left"
...
  <TextBlock HorizontalAlignment="Right"
...
/Grid>

我几乎专门使用网格(Grid),为每个“属于一起”的元素块使用单独的网格。

我不认为 DockPanel 是邪恶的,它们有时可能非常有用... 但是我必须同意,在那种情况下它可能不是最佳选择。 - Thomas Levesque
当然,这是主观的,它们并不是绝对的邪恶;)但是看看Rich已经走到哪里了——使用ItemContainerStyle(半高级的东西)来完成简单的任务——有点说明问题... - Sergey Aldoukhov
我一开始考虑使用网格(Grid)。然而,如果使用狭窄的ListBox或者Name或Price属性值足够长,那么这两个TextBlock的值将会重叠。此外,我几乎不认为在面板的两端布置两个TextBlock是一个“复杂的布局”。 - Richard McGuire
抱歉对这篇老帖子发表评论,但使用网格也是解决这个问题的一个简单而同样有效的方法。避免重叠问题。+1 - code4life
这是一个旧答案,但我想指出,在ListBox的项模板中使用网格或面板的问题在于它不是一个单一的元素;它是每个ListBoxItem的新元素,并且除非在模板中明确设置,否则不会共享任何其他项的宽度。当使用动态宽度时,这使得设置ItemContainerStyle内容对齐方式为stretch成为必要。 - Tim
停靠面板是一个诱惑,因为新手们期望它们像 Windows Forms 的停靠面板一样工作,或者即便是 QT 和 MFC 的版本也可以。我发现它们更加麻烦,需要更多额外的工作才能达到相同的结果。网格通常是你想要的,因为它们很灵活。WPF 似乎非常可定制,类似于 QT Quick,但在 WPF 和 XAML 首次发明时,对于它们来说,代码与展示/设计之间的分离是如此重要的(还记得没有智能感知的时候吗?)。 - osirisgothra

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接