在WPF中为WrapPanel指定最大列数

23

我有一个WrapPanel,我想指定它的最大列数。例如,当我的“ObjectCollection”集合(绑定到此WrapPanel)仅包含4个元素时,WrapPanel将只有一行。但是,当“ObjectCollection”有5个元素时,WrapPanel将创建另一行来放置第五个元素。(在这种情况下,我的Max_Columns_Number为4)。


你不需要为此编写自定义面板,只需在ListBox中使用Grid代替WrapPanel作为ItemsPanel即可。但是,您需要告诉每个ListBoxItem属于哪个网格行或列。 - ninja hedgehog
4个回答

50

我相当确定你无法使用WrapPanel实现,但可以使用UniformGrid代替。

该控件具有指定所需行数和列数的属性。

如果将Columns属性设置为4,则它会在每行保持4个项目,然后换到下一行。

<UniformGrid Columns="4">
    <!-- In first row -->
    <Button Content="test"></Button>
    <Button Content="test"></Button>
    <Button Content="test"></Button>
    <Button Content="test"></Button>

    <!-- In second row -->
    <Button Content="test"></Button>
</UniformGrid>

非常感谢!我在使用WrapPanel的时候遇到了一些困难,这个解决方案非常适合我。 - upizs
非常感谢!我在使用WrapPanel时遇到了困难,这个解决方案对我来说更加顺利。 - undefined

9
基本上,你需要为自己创建一个自定义的Panel……现在不要沮丧……这并不是很难。首先,请查看我提供链接的文章,了解如何创建自定义Panel

如何在WPF中创建自定义布局面板

在WPF中创建自定义面板

好的,现在你知道了更多关于创建自定义Panel的知识,我们可以继续了……下面是你需要的内容:
private int columnCount;
private double leftColumnEdge, rightColumnEdge, columnWidth;

public int ColumnCount
{
    get { return columnCount; }
    set
    {
        if (value < 1) value = 1;
        columnCount = value;
    }
}

这个属性将用于在“资源”中声明Panel的位置:
<ItemsPanelTemplate x:Key="AnimatedPanel">
    <Controls:AnimatedColumnWrapPanel ColumnCount="3" ... />
</ItemsPanelTemplate>

请注意,您需要在ItemsPanelTemplate对象内部声明它,因为这是ItemsPanel属性所期望的内容:
 <ListBox ItemsPanel="{StaticResource AnimatedPanel}" ... />

现在回到Panel......这里有一个帮助方法,我从MeasureOverrideArrangeOverride方法中调用:
private void UpdateColumns(int currentColumn, Size finalSize)
{
    leftColumnEdge = (finalSize.Width / ColumnCount) * currentColumn;
    rightColumnEdge = (finalSize.Width / ColumnCount) * (currentColumn + 1);
    columnWidth = rightColumnEdge - leftColumnEdge;
}

很抱歉,我不能提供完整的示例,因为我的自定义Panel都与基础的AnimatedPanel类绑定,具有许多其他功能。但是,您只需要创建MeasureOverrideArrangeOverride方法即可完成此Panel。如果您仔细思考,它其实并不难。


这是专业级别的。这更适合你或我 :) 他似乎不理解布局。他最好使用Grid或UniformGrid。 - ninja hedgehog
1
我完全接受这一点,但希望随着时间的推移,一些用户会发现这个页面有用。 - Sheridan
当然,那里有很多事情要处理。测量钻取过程、计算、排列等等。但是是否从头开始还是由用户决定。 - ninja hedgehog

1
有时候UniformGrid不够用:
  • 当项目大小非常不同,或者
  • 当您想要垂直排列项目并且不想使用其他解决方法
这个stackoverflow帖子中可以找到一个WrapPanel,其中包含您正在寻找的内容。 Xaml:
<loc:WrapPanelWithRowsOrColumnsCount
    xmlns:loc="clr-namespace:..."
    Orientation="Vertical"
    RowsOrColumnsCount="2">
    <TextBox Text="Andrew" Margin="2" Height="30" />
    <TextBox Text="Betty" Margin="2" Height="40" />
    <TextBox Text="Celine" Margin="2" Height="20" />
    <TextBox Text="Dick" Margin="2" Height="20" />
    <TextBox Text="Enron" Margin="2" Height="30" />
    <TextBox Text="Felix" Margin="2" Height="20" />
    <TextBox Text="Hanibal" Margin="2" Height="30" />
</loc:WrapPanelWithRowsOrColumnsCount>

结果:

enter image description here


1
您可以通过设置包装面板的宽度来控制列数。我将包装面板的宽度绑定到容器(如边框)的ActualWidth上。这样,列数是动态的,并基于窗口的宽度。
<Border Name="DataBorder" Grid.Row="0" Grid.Column="1"
        BorderBrush="Navy" BorderThickness="1,2,2,2"
        Padding="4">
        <Grid>
             <Grid.RowDefinitions>
                  <RowDefinition Height="Auto"></RowDefinition>
                  <RowDefinition Height="*"></RowDefinition>
              </Grid.RowDefinitions>

              <StackPanel>
                  <TextBlock Text="{Binding NewPictureCountDisplay}"></TextBlock>
              </StackPanel>

              <ListBox Name="NewFilesListBox" Grid.Row="1"
                       ItemsSource="{Binding CreatedFiles}">
                  <ListBox.ItemsPanel>
                      <ItemsPanelTemplate>
                          <WrapPanel Orientation="Horizontal" Width="{Binding ElementName=DataBorder, Path=ActualWidth}"></WrapPanel>
                      </ItemsPanelTemplate>
                  </ListBox.ItemsPanel>
                        <ListBox.ItemTemplate>
                            <DataTemplate>
                                <Grid>
                                    <Grid.RowDefinitions>
                                        <RowDefinition Height="*"></RowDefinition>
                                        <RowDefinition Height="Auto"></RowDefinition>
                                    </Grid.RowDefinitions>

                                    <Image Grid.Row="0" Source="{Binding FullPath}" Width="128" Height="128" Stretch="UniformToFill"></Image>

                                    <StackPanel Grid.Row="1" Orientation="Vertical">
                                        <Button Content="Import" Margin="2"></Button>
                                        <Button Content="Delete" Margin="2"></Button>
                                        <TextBlock HorizontalAlignment="Stretch" Text="{Binding FullPath}" Margin="2"></TextBlock>
                                        <TextBlock HorizontalAlignment="Stretch" Text="{Binding ChangeType}" Margin="2"></TextBlock>
                                    </StackPanel>

                                </Grid>
                            </DataTemplate>
                        </ListBox.ItemTemplate>
                    </ListBox>

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