WrapPanel is great, so please, stop using it!

The WrapPanel control (part of the Windows Phone Toolkit) is a really useful control container.

Having said that, you should definitely avoid using it in your apps if you are planing to use in ListBox.ItemsPanel for large lists items presented with fixed size!!

To demonstrate my point, let’s say we have a list of 10 items:

{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}

Now say we want to list 3 items per row and them wrap to the next row, we can use a WrapPanel container control, like so:

<ListBox x:Name="ItemsListBox"
            ItemTemplate="{StaticResource ItemDataTemplate}">
            <toolkit:WrapPanel />

The resulting items layout will look something like the following picture:

WrapPanel layout

This will work fine with 10 items, but what about 100? Or 1.000? Or even 10.000?

Using a WrapPanel with a large number of items will cause the control loading time and memory usage to increase, and if you make it large enough, you’ll probably start seeing your app crash with “out of memory” errors…

Now lets say we first group the items in groups of 3, making the source list look like this:

{ {0, 1, 2}, {3, 4, 5}, {6, 7, 8}, {9} }

All we now need is another ItemsControl inside our main ListBox to iterate the each group, something like this:

<ListBox x:Name="ItemsListBox">
            <ItemsControl ItemTemplate="{StaticResource ItemDataTemplate}" ItemsSource="{Binding}">
                        <VirtualizingStackPanel Orientation="Horizontal" />

Here’s the resulting layout schematic:

Smart Wrapping layout

Major advantages with this approach is the obvious performance improvement and memory consumption reduction. Why? Because we maintained the VirtualizingStackPanel in our main ListBox.ItemsPanel!

To prove my point, I’ve created a small demonstration app showing the result of using these two approaches with a list of 400 items.

Smart Wrapping Demo (914.91 kB)
Downloaded 1655 times

Download the code, deploy it on a phone or emulator, then run each approach separately and exit the app after each run in order to check the peak memory usage.

You’ll notice a huge difference in loading times, but I can tell you that memory wise, it’s the difference between using 120MB or just 20MB! πŸ™‚

  • Or just as good, use the LongListSelector and set the LayoutMode to be Grid (remembering to set the GridCellSize property.

    • Excellent point there!! I’m not entirely sure if the LongListSelector in Grid mode is actually virtualized, but assuming it is, I’d definitely go for it!

      • I’ve ran a quick test and confirmed that LongListSelector in Grid mode has a small memory print and loading is really fast, so I guess we can assume it is being virtualized and just use it as the preferred (easier?) approach!

  • How about an ItemsControl instead of the ListBox?

    • ItemsControl.ItemsPanel isn’t set to use a VirtualizingStackPanel by default, so as long as you set it to that, it will work fine! πŸ™‚

  • Yaroslav

    Great, but what about the selection… How would you select one ListBox item instead of three in a row?

    • My article was mainly focused on solving the performance and memory issues that some people see when using the WrapPanel, selection wan’t exactly the point on it… some extra work would be involved to get selection working, but if you are developing for WP8, you can always use the LongListSelector as @ScottLovegrove:disqus pointed out in his comment! πŸ™‚

  • Matheus Lustosa

    Thanks for the tip. Is MS planing to make the Wrap Panel use a VirtualizingPanel any time soon? Although your proposed approach works well it seems as a work around for a simple problem.

  • Pingback: Weekly Digest for Developers: Mar 24 - Mar 30, 2014 | Super Dev Resources()

  • Frodo

    It works, but the data do not stretch, to the right is the free space. This is a detailed description of my problem – http://stackoverflow.com/questions/26506675/listboxitem-does-not-stretch-in-listbox . How to solve it?