Click here to Skip to main content
Click here to Skip to main content

Custom ListBox Layout in WPF

, 26 Apr 2007 CPOL
Rate this:
Please Sign up or sign in to vote.
A step-by-step review of how to customize the arrangement of items in a ListBox.


This article explores how to customize the way that items are arranged in a ListBox (or any ItemsControl subclass). It makes use of the ItemsPanel property to perform the customization.


I had an "Aha!" moment one day when I discovered the ItemsPanel property of ItemsControl. This property allows you to choose the layout panel used to arrange items displayed in an ItemsControl or any control which derives from it, such as ListBox. This feature is evidence of the incredible flexibility in WPF because it allows you to completely redefine how the items in a list should be arranged, relative to one another.

The demo application shown here populates a ListBox with images of toy robots. Initially the images are listed from the top of the ListBox down to the bottom, which is the normal behavior. After the customization is complete, the images will be displayed in a left-to-right top-to-bottom layout, like text on a page (for us left-to-right readers). This custom layout is achieved by using a WrapPanel to arrange the images for us.

Step one – Putting a ListBox in a Window

The implementation of this task can be broken into four logical steps. The first step is just to put a ListBox into a Window.

<Window x:Class="CustomItemsPanel.Window1"
  Title="Custom ItemsPanel" Height="600" Width="260"
  <!--<span class="code-comment"> This ListBox is the Content of the Window.
       Normally you would have a panel of some type
       as the Window's Content, but let's keep it simple. --></span>
  <ListBox ItemsSource="{Binding}" />

If you compile and run the project at this point, you will see what appears to be an empty Window. The ListBox is displayed there; however, it has no items in it yet.

Step two – Filling the ListBox with pictures

Next let's see the class which is used to populate the ListBox with images of robots.

public static class RobotImageLoader
  public static List<BitmapImage> LoadImages()
    List<BitmapImage> robotImages = new List<BitmapImage>();
    DirectoryInfo robotImageDir = new DirectoryInfo( @"..\..\Robots" );
    foreach( FileInfo robotImageFile in robotImageDir.GetFiles( "*.jpg" ) )
      Uri uri = new Uri( robotImageFile.FullName );
      robotImages.Add( new BitmapImage( uri ) );
    return robotImages;

The simple code above assumes that your project has a folder named "Robots" and it contains some JPG images. In a more realistic application, these types of hard-coded dependencies should be externalized into a configuration system. We can make use of the RobotImageLoader class with the following markup in the Window class declared above:

    ObjectType="{x:Type local:RobotImageLoader}"

The XAML above indicates that the implicit data source for all visual elements in the Window will, by default, be the object returned when calling the static RobotImageLoader.LoadImages method.

If you run the application now and resize the Window a bit, it looks like this:

Screenshot - CustomItemsPanel_NoTemplate.png

The screenshot seen above is obviously not what we had in mind. It would be much nicer if we could see the image stored within a BitmapImage, instead of the image's URI. The reason it is displaying a URI is because a BitmapImage object has no intrinsic support for displaying itself. When the ListBox renders each BitmapImage object, it ends up calling the ToString method on the object because BitmapImage does not derive from the UIElement class. It then displays the string returned from the BitmapImage object's ToString override.

Step three – Creating a template to display pictures

The next step is to explain to the ListBox how it should render a BitmapImage. To accomplish this, we will apply a Style to the ListBox. The Style will set the ListBox's ItemTemplate property to a DataTemplate, which specifies that an Image element wrapped in a Border should be displayed when trying to render a BitmapImage object.

Here's the modified XAML:

<Window x:Class="CustomItemsPanel.Window1"
    Title="The images are shown" Height="600" Width="260"
    <Style TargetType="{x:Type ListBox}">
      <!--<span class="code-comment"> Set the ItemTemplate of the ListBox to a DataTemplate which
           explains how to display an object of type BitmapImage. --></span>
      <Setter Property="ItemTemplate">
            <Border BorderBrush="Black" BorderThickness="4"
              CornerRadius="5" Margin="6"
                Source="{Binding Path=UriSource}"
                Width="100" Height="120"

      ObjectType="{x:Type local:RobotImageLoader}"
      MethodName="LoadImages" />

  <!--<span class="code-comment"> This ListBox is the Content of the Window.
       Normally you would have a panel of some type
       as the Window's Content, but let's keep it simple. --></span>
  <ListBox ItemsSource="{Binding}" />

If you run the application now, it looks like this:

Screenshot - CustomItemsPanel_WithTemplate.png

Ah, that's much better. Notice, though, that the user would have to scroll down if he/she wanted to see more of the robots. Perhaps the logic of this application requires that the user should be able to see as many robots as possible in the Window. This is when the ItemsPanel property saves the day.

Step four – Replacing the default items panel

By default the ListBox uses what's called a VirtualizingStackPanel to display its items. Basically, a VirtualizingStackPanel is a StackPanel that only creates visual objects for the items that are currently viewable in the control. For items that are scrolled out of view, the panel throws away the visual objects used to render them. This technique can drastically improve performance and memory consumption when the control has a large number of items.

For situations where a VirtualizingStackPanel is not the ideal layout mechanism for items in the ListBox, we can specify any panel we would like to display the items. A good choice for our situation here is to use the WrapPanel to host the ListBox's items. The WrapPanel, by default, will arrange its children from left to right and, when it runs out of horizontal space, it will create another row of items beneath the previous row. It keeps following that pattern until all of the items are displayed. When the WrapPanel is resized it will update the layout to ensure that as many of the items are entirely in view as possible.

The last step is to set the ListBox's ItemsPanel property to a WrapPanel. The following XAML would also be placed in the Style seen in the previous snippet:

<!--<span class="code-comment"> Swap out the default items panel with a WrapPanel so that
     the images will be arranged with a different layout. --></span>
<Setter Property="ItemsPanel">
      <WrapPanel />

<!--<span class="code-comment"> Set this attached property to 'Disabled' so that the
     ScrollViewer in the ListBox will never show a horizontal
     scrollbar, and the WrapPanel it contains will be constrained
     to the width of the ScrollViewer's viewable surface. --></span>

When you run the application now, it looks like this:

Screenshot - CustomItemsPanel_WrapPanel.png

If you were to resize the Window, the WrapPanel would adjust the layout to accommodate the new dimensions. For example:

Screenshot - CustomItemsPanel_WrapPanel_Wide.png

There is one important thing to notice in the XAML seen above. It is necessary to specify that the ScrollViewer inside the ListBox disables its horizontal scrollbar. Doing so ensures that the width of the WrapPanel is constrained to the viewable width of the ScrollViewer. It also prevents the horizontal scrollbar from ever appearing, which is desirable in this scenario. Here's the XAML in the <Style> which sets that property:


The source code for this demo project can be downloaded at the top of this article.


  • April 25, 2007 – Created article


This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


About the Author

Josh Smith
Software Developer (Senior) Cynergy Systems
United States United States
Josh creates software, for iOS and Windows.

He works at Cynergy Systems as a Senior Experience Developer.

Read his iOS Programming for .NET Developers[^] book to learn how to write iPhone and iPad apps by leveraging your existing .NET skills.

Use his Master WPF[^] app on your iPhone to sharpen your WPF skills on the go.

Check out his Advanced MVVM[^] book.

Visit his WPF blog[^] or stop by his iOS blog[^].
Follow on   Twitter

Comments and Discussions

QuestionWhat to do with multiple listboxes PinmemberMember 103478268-Feb-15 6:29 
QuestionNot all images getting shown PinmemberMember 941564618-Jun-14 5:31 
QuestionHow to go through the whole list? ( using Right arrow key) [modified] PinmemberMember 959381112-Jun-14 5:22 
GeneralMy vote of 5 PinmemberBruno Costa Bourbon6-Jun-14 4:52 
QuestionVirtualize PinmemberDunge14-Mar-14 19:51 
Questionidea PinmemberPinigonzalez2-Jul-13 1:24 
GeneralMy vote of 5 PinmemberMember 78556819-Feb-13 16:50 
GeneralMy vote of 5 PingroupTheingi Win21-Aug-12 16:14 
GeneralGood sample PinmemberInba karthik2-Jul-12 20:05 
GeneralMy vote of 5 PinmemberMika199210-Mar-12 7:16 
GeneralMy vote of 5 PinmemberMember 200105318-Oct-11 18:07 
QuestionCoordinates of images. Pinmembersaisunil30-Sep-11 9:01 
GeneralMy vote of 5 PinmemberWil Peck10-Jun-11 8:18 
GeneralSuperb Article Pinmemberphil24157-Jun-11 1:12 
Generalthanks Pinmembercuipengfei20-Feb-11 18:52 
GeneralMy vote of 5! PinmemberTarun.K.S27-Oct-10 2:42 
GeneralMy vote of 5 Pinmemberla015-Oct-10 16:01 
GeneralRandom rotated items. Problem with selected Image. [modified] PinmemberTingleTangle16-Aug-10 8:32 
GeneralThank you very much PinmemberMember 149481128-Jul-10 1:06 
GeneralA Question regarding Non Symmetric Layout [modified] PinmemberRunUFool20-Jul-10 0:04 
Generalthank you Pinmembergiandeibrughi11-May-10 1:32 
Questionany idea how to use both vertical and horizontal scroll for very large number of images above? Pinmemberfunny_hacks8-Apr-10 3:52 
QuestionHow would you make the items wrap vertically Pinmemberbig red1-May-09 8:29 
AnswerRe: How would you make the items wrap vertically PinmvpJosh Smith1-May-09 9:17 
QuestionRectangular selecting multiple items Pinmembertomi_21-May-09 4:47 
GeneralThank You! Thank You! Thank You! Pinmemberomni969-Mar-09 15:00 
GeneralRe: Thank You! Thank You! Thank You! PinmvpJosh Smith9-Mar-09 16:39 
GeneralRe: Thank You! Thank You! Thank You! Pinmembertomi_230-Apr-09 15:21 
QuestionAny idea how to make combolist to look like this? PinmemberHardy Wang29-Dec-08 12:33 
QuestionFirst Visible Item of List PinmemberAVEbrahimi13-Nov-08 21:35 
Hi Josh:

How can I change ( or find) first visible item of ListBox?

GeneralYeah! :) Pinmemberprogrammeur19-Jun-08 8:55 
GeneralDam Pinmembersinghswat11-Jun-08 18:34 
GeneralZoomable listbox Pinmemberfanoo3-Jul-07 5:45 
GeneralRe: Zoomable listbox PinmvpJosh Smith3-Jul-07 6:10 
GeneralBig Thanks! PinmemberKarl_Shifflett17-Jun-07 16:15 
GeneralRe: Big Thanks! PinmvpJosh Smith17-Jun-07 17:20 
GeneralResizable ListBoxItems PinmemberStefano,7-Jun-07 3:13 
Generalthanks Pinmemberben0909025-May-07 12:32 
GeneralRe: thanks PinmvpJosh Smith25-May-07 13:56 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Terms of Use | Mobile
Web02 | 2.8.150331.1 | Last Updated 26 Apr 2007
Article Copyright 2007 by Josh Smith
Everything else Copyright © CodeProject, 1999-2015
Layout: fixed | fluid