While working on a current project, I wanted to create a wrapping ListBox. This is one where the items are not simply stacked on top of each other. Instead, the items either travel left-to-right, then wrap back around (like when you’re typing) with a vertical scrollbar, or travel top-to-bottom, then wrap around to the top again with a horizontal scrollbar. For examples, look at Windows Vista Explorer. Tiles view is a left-to-right wrapping ListBox, and List view is a top-to-bottom wrapping ListBox.

The Silverlight Toolkit includes a WrapPanel. So I thought I could do the following:

<ListBox x:Name="lboWrapListBox">
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<controls:WrapPanel Orientation="Horizontal" />
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
</ListBox>

After adding my items, I noticed that the WrapPanel was not wrapping at all. There are 2 solutions.

The first solution is to give the WrapPanel object an explicit width. For example:

<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<controls:WrapPanel Orientation="Horizontal" Width="300"/>
</ItemsPanelTemplate>
</ListBox.ItemsPanel>


This works, but it makes the ListBox non-resizable if the browser or control changes size.



After some assistance on the Silverlight.net forums, I figured out what’s needed. An ItemsPresenter needs to be added to the template for the ListBox:



<ListBox.Template>
<ControlTemplate>
<ItemsPresenter />
</ControlTemplate>
</ListBox.Template>

After adding this, the ListBox now wraps. However, there are no scrollbars, so the ListBox wraps, but you can’t get to any items offscreen. We can remedy this by wrapping the ItemsPresenter in a ScrollViewer:

<ListBox.Template>
<ControlTemplate>
<ScrollViewer>
<ItemsPresenter />
</ScrollViewer>
</ControlTemplate>
</ListBox.Template>

Now we have a properly wrapping and scrolling wrapping ListBox.

But what about a vertically wrapping ListBox?

If I change the Orientation from Horizontal to Vertical on the WrapPanel, we lose wrapping, but we’ve kept scrolling. If we now remove the ScrollViewer from around the ItemsPresenter, wrapping is restored, but we’ve now lost the scrolling capability.

At this point, I am unaware of the solution. Hopefully I’ll come up with something. Maybe the Silverlight Toolkit Team can fix this in the WrapPanel itself. In the meantime, below are some final styles which you can use to create a wrapping ListBox.

<Style x:Key="HorizontalWrapListBox" TargetType="ListBox">
<Style.Setters>
<Setter Property="ItemsPanel">
<Setter.Value>
<ItemsPanelTemplate>
<controls:WrapPanel Orientation="Horizontal" />
</ItemsPanelTemplate>
</Setter.Value>
</Setter>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ListBox">
<ScrollViewer>
<ItemsPresenter />
</ScrollViewer>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style.Setters>
</Style>

<Style x:Key="VerticalWrapListBox" TargetType="ListBox">
<Style.Setters>
<Setter Property="ItemsPanel">
<Setter.Value>
<ItemsPanelTemplate>
<controls:WrapPanel Orientation="Vertical" />
</ItemsPanelTemplate>
</Setter.Value>
</Setter>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ListBox">
<ItemsPresenter />
</ControlTemplate>
</Setter.Value>
</Setter>
</Style.Setters>
</Style>

You can use it as follows:

<ListBox x:Name="lboWrapListBox"
Style="{StaticResource HorizontalWrapListBox}" />

Note that the VerticalWrapListBox does not scroll properly. If your ListBox has a static size (ie. is not going to change sizes), then you can get around this by explicitly setting a height on the WrapPanel control.