I have a WrapPanel, And I want to specify the Max number of its columns. So, for example, when my Collection \"ObjectCollection\" (binded to this WrapPanel) contains only 4 elem
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>
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>
Sometimes the UniformGrid is not enough:
In this stackoverflow post can be found a WrapPanel with what you are searching for.
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>
Result:
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 Panel
s, 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 Panel
s 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.