首页 > 解决方案 > 如何设置垂直 WPF WrapPanel 以使用尽可能多的列

问题描述

我有一个带有 WrapPanel 作为 ItemsPanel 的 ItemsControl。ItemsControl 位于 ScrollViewer 中。

根据窗口的宽度,ItemsControl/WrapPanel 应该有更多的列来更多地使用屏幕(并且用户必须减少滚动)。

如果我将 WrapPanel 设置为 Orientation="Horizo​​ntal" 它会按预期工作。但是,如果我将方向设置为“垂直”,则 ItemsControl/WrapPanel 仅显示一列。

不同的是,我喜欢这些专栏就像报纸专栏一样,比如:

A   E   I
B   F   J
C   G
D   H

但是,如果 WrapPanel 设置为 Horizo​​ntal,则列如下:

A   B   C
D   E   F
G   H   I
J

如何将 WrapPanel 设置为这样?

我当然可以限制高度。当然,我可以通过一些巧妙的逻辑来实现这一点,即考虑到源中的项目数量以及窗口的宽度。但这会很复杂,而且可能是一团糟,其他人都不会理解(甚至我自己,如果我在几年内回顾一下)。

我希望这样的东西已经存在于 WPF 中。


这是伪 XAML 代码

<ScrollViewer>
    <StackPanel>

        <!-- Some other stuff -->

        <ItemsControl ItemsSource="{Binding … }">
            <ItemsControl.ItemsPanel>
                <ItemsPanelTemplate>
                    <WrapPanel Orientation="Vertical" />
                </ItemsPanelTemplate>
            </ItemsControl.ItemsPanel>
            <ItemsControl.ItemTemplate>
                <DataTemplate>
                    <Grid Width="300"><!-- … --></Grid>
                </DataTemplate>
            </ItemsControl.ItemTemplate>
        </ItemsControl>

        <!-- Some more other stuff -->

    </StackPanel>
</ScrollViewer>

它适用于 Orientation="Horizo​​ntal"(但随后单元格的顺序错误),但在 Orientation="Vertical" 时仅显示一列。

标签: wpforientationwrappanel

解决方案


好的,我想出了一个解决方案,那就是纯 XAML。

所以基本上我有一个网格。有两排。网格内部是两个几乎相同的 ItemsControl,带有绑定和 WrapPanel。第一个有一个带有 Orientation="Horizo​​ntal" 的 WrapPanel。它仅用于计算第二个 ItemsControl 的边界。因此它的可见性=“隐藏”。它也只跨越第一行。

第二个 ItemsControl 具有 Orientation="Vertical" 的 WrapPanel。它的高度绑定到第一个 ItemsControl 的 ActualHeight。因此它被迫使用多个列,因为高度不能高于 ItemsControl #1 的高度。第二个 ItemsControl 跨越两行(这很重要,否则高度可能会卡住,调整窗口大小*)。

这不是一个很好的解决方案。更像是蛮力。但它当然有效。第一个 ItemsControl 计算外部尺寸。我将这个尺寸强制为第二个,这样可以很好地分配物品。

<ScrollViewer>
    <StackPanel>

        <!-- Some other stuff -->

        <Grid>
            <Grid.RowDefinitions>
                <RowDefinition/>
                <RowDefinition/>
            </Grid.RowDefinitions>

            <!-- first ItemsControl, to calculate the outer boundaries with --> 
            <ItemsControl ItemsSource="{Binding … }" 
                          Name="Calculating_Size"
                          Visibility="Hidden">
                <ItemsControl.ItemsPanel>
                    <ItemsPanelTemplate>
                        <WrapPanel Orientation="Horizontal" />
                    </ItemsPanelTemplate>
                </ItemsControl.ItemsPanel>
                <ItemsControl.ItemTemplate>
                    <DataTemplate>
                        <Grid Width="300"><!-- … --></Grid>
                    </DataTemplate>
                </ItemsControl.ItemTemplate>
            </ItemsControl>

            <!-- Second ItemsControl with fixed size for Vertical WrapPanel --> 
            <ItemsControl ItemsSource="{Binding … }" 
                          Height="{Binding ActualHeight, ElementName=Calculating_Size}"
                          Grid.RowSpan="2">
                <ItemsControl.ItemsPanel>
                    <ItemsPanelTemplate>
                        <WrapPanel Orientation="Vertical" />
                    </ItemsPanelTemplate>
                </ItemsControl.ItemsPanel>
                <ItemsControl.ItemTemplate>
                    <DataTemplate>
                        <Grid Width="300"><!-- … --></Grid>
                    </DataTemplate>
                </ItemsControl.ItemTemplate>
            </ItemsControl>

        <!-- Some more other stuff -->

    </StackPanel>
</ScrollViewer>



* 第二行的原因是,如果第一个 WrapPanel 重新组织,因为宽度增加,它仍然与高度固定,因为行不能变小,第二个 ItemsControl。但是,如果第二个 ItemsControl 跨越两行,则第一行可以独立于第二个 ItemsControl 变得更小。之后第二个立即变小。但这似乎是一个额外的步骤。


推荐阅读