This article presents a
ListBox-derived control which slides its items when they are selected and deselected. The
SlidingListBox allows you to customize the animated sliding of its items so that you can make it “feel right” in your applications. The effect provided by the
SlidingListBox can help make your user interfaces more intuitive and interactive for the users, which is always a good thing.
The code presented here was compiled and tested against the RC1 of the .NET Framework 3.0.
ListBox control is very flexible and has features far beyond the standard WinForms
ListBox. This article does not discuss the the fundamentals of the WPF
ListBox, but if you want to learn more about it I recommend Mike Hillberg’s excellent blog entry “Brief Anatomy of a ListBox”.
There is one important thing to know about the default
ItemTemplate, which is relevant in this article. By default, each item's visual tree will consist of a
Border, which contains a
ContentPresenter contains the visuals pertaining to the items underlying data object. The fact that the
ContentPresenter is wrapped in a
Border is very important to the internal workings of the
SlidingListBox, as we see later on.
Using the SlidingListBox
SlidingListBox can be used just like the regular
ListBox, except you have three more properties to play with. Below is some XAML which creates and configures the control:
The XAML above creates a
SlidingListBox whose items are aligned to the right side of the control, and when an item is selected it will slide to the left by fifty logical pixels over the course of 250 milliseconds. The snippet above shows the three dependency properties declared by the
SlideDirection – This property allows you to specify what direction the selected item(s) should be slid. You can choose ‘Up’, ‘Down’, ‘Right’, or ‘Left’. You would probably only use the ‘Up’ or ‘Down’ options if the controls
ItemsPanel was set to a panel which lays out the items horizontally. The default value is ‘Right’.
SlideDistance – This property allows you to specify a positive number of logical pixels which the selected item(s) are slid. The default value is 20.0.
SlideDuration – This property allows you to indicate a positive number of milliseconds that determines how long the sliding animation should last. The default value is 200.
The demo application, which can be downloaded at the top of this article, shows how the various values of these properties affect the behavior of the sliding animations. If you plan on using the
SlidingListBox in your applications, you can play around with the property values in that demo to get a feel for how you like the control to be configured.
How it Works
As I mentioned in the Background section of this article, the default
ListBox ItemTemplate wraps an items visual tree in a
SlidingListBox depends on that
Border being there, because it achieves the sliding effect by animating the
For example, suppose that there is a
SlidingListBox whose items slide to the right by 50 logical pixels when selected. When an item in the
SlidingListBox is selected, the
SlidingListBox finds the
Border in that items visual tree. It then animates the
Padding property so that the
Padding.Left ends up being incremented by 50. When that
ListBoxItem is subsequently deselected, the
Padding is animated back to its original state.
There is not too much code involved with getting the sliding animation to happen. The following two methods are members of the
protected override void OnSelectionChanged( SelectionChangedEventArgs e )
base.OnSelectionChanged( e );
ItemContainerGenerator generator = this.ItemContainerGenerator;
if( generator.Status != GeneratorStatus.ContainersGenerated )
for( int i = 0; i < this.Items.Count; ++i )
ListBoxItem item = generator.ContainerFromIndex( i ) as ListBoxItem;
if( VisualTreeHelper.GetChildrenCount( item ) == 0 )
Border rootBorder = VisualTreeHelper.GetChild( item, 0 ) as Border;
if( rootBorder == null )
this.AnimateItem( item, rootBorder );
void AnimateItem( ListBoxItem item, Border rootBorder )
if( item.IsSelected )
ListBoxItemSlideDirection direction = this.SlideDirection;
if( direction == ListBoxItemSlideDirection.Up )
thickness = new Thickness( 2, 0, 0, this.SlideDistance );
else if( direction == ListBoxItemSlideDirection.Right )
thickness = new Thickness( 2 + this.SlideDistance, 0, 0, 0 );
else if( direction == ListBoxItemSlideDirection.Down )
thickness = new Thickness( 2, this.SlideDistance, 0, 0 );
thickness = new Thickness( 2, 0, this.SlideDistance, 0 );
thickness = new Thickness( 2, 0, 0, 0 );
TimeSpan timeSpan = TimeSpan.FromMilliseconds( this.SlideDuration );
Duration duration = new Duration( timeSpan );
ThicknessAnimation anim = new ThicknessAnimation( thickness, duration );
rootBorder.BeginAnimation( Border.PaddingProperty, anim );
One quirk that the sliding animation code has to deal with is that the
Border in a
ItemTemplate has its
Padding.Left set to 2. The code which creates the
Thickness used in the animation accounts for this by always ensuring that the
Left is at least 2.
Feel free to use the
SlidingListBox in your WPF applications. All that I ask is that the Copyright blurb at the top of SlidingListBox.cs remains intact. If you think of any cool new features or (gasp) find any bugs, please let me know about it.