Specify the max number of columns for a WrapPanel in WPF Specify the max number of columns for a WrapPanel in WPF wpf wpf

Specify the max number of columns for a WrapPanel in WPF


I'm pretty sure you can't do it with a WrapPanel, but you can use the UniformGrid instead.

That one has properties to specify the number of rows and columns you want.

If you set the Columns property to 4, it will keep 4 items in each row, and then wrap to the next one.

<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>


Basically you're going to need to create a custom Panel for yourself... now don't get despondent... it's not that difficult. To start with, please take a look at the posts that I have provided links for that explain how to create a custom Panel:

How to create a Custom Layout Panel in WPF

Creating Custom Panels In WPF

Ok, so now that you know a bit more about creating custom Panels, we can continue... here's what you're going to need:

private int columnCount;private double leftColumnEdge, rightColumnEdge, columnWidth;public int ColumnCount{    get { return columnCount; }    set    {        if (value < 1) value = 1;        columnCount = value;    }}

This property would be used where you declare your Panel in Resources:

<ItemsPanelTemplate x:Key="AnimatedPanel">    <Controls:AnimatedColumnWrapPanel ColumnCount="3" ... /></ItemsPanelTemplate>

Note that you will need to declare it inside an ItemsPanelTemplate object because that is what the ItemsPanel property expects:

 <ListBox ItemsPanel="{StaticResource AnimatedPanel}" ... />

Now back to the Panel... here is a helper method that I call from the MeasureOverride and ArrangeOverride methods:

private void UpdateColumns(int currentColumn, Size finalSize){    leftColumnEdge = (finalSize.Width / ColumnCount) * currentColumn;    rightColumnEdge = (finalSize.Width / ColumnCount) * (currentColumn + 1);    columnWidth = rightColumnEdge - leftColumnEdge;}

Unfortunately for you, I cannot provide you with a complete example because my custom Panels are all tied into a base AnimatedPanel class with lots of additional functionality. However, you only need to create the MeasureOverride and ArrangeOverride methods to complete this Panel. If you just think logically about it, it's really not that difficult.


You can control the number of columns by setting the width of the wrap panel. I bind the width of the wrap panel to the ActualWidth of a container like Border. That way, the number of columns is dynamic and is based on the width of the window.

<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>