Click here to Skip to main content
15,868,016 members
Articles / Desktop Programming / WPF
Article

SlidingListBox – Animating ListBoxItems in WPF

Rate me:
Please Sign up or sign in to vote.
4.91/5 (25 votes)
19 Oct 2006CPOL4 min read 146.6K   5.2K   78   21
A ListBox which slides its items when they are selected and deselected.

Sample Image - SlidingListBox.png

Introduction

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.

Background

The WPF 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 ListBox ItemTemplate, which is relevant in this article. By default, each item's visual tree will consist of a Border, which contains a ContentPresenter. The 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

The 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:

XML
<jas:SlidingListBox 
  HorizontalContentAlignment="Right" 
  SlideDirection="Left"
  SlideDistance="50"
  SlideDuration="250"
 />

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 SlidingListBox class:

  • 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 Border. The SlidingListBox depends on that Border being there, because it achieves the sliding effect by animating the Border’s Padding property. 

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 Border’s Padding property so that the Padding.Left ends up being incremented by 50. When that ListBoxItem is subsequently deselected, the Borders 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 SlidingListBox class:

C#
protected override void OnSelectionChanged( SelectionChangedEventArgs e )
{
    base.OnSelectionChanged( e );

    ItemContainerGenerator generator = this.ItemContainerGenerator;
    if( generator.Status != GeneratorStatus.ContainersGenerated )
        return; 

    for( int i = 0; i < this.Items.Count; ++i )
    {
        ListBoxItem item = generator.ContainerFromIndex( i ) as ListBoxItem;
        if( VisualTreeHelper.GetChildrenCount( item ) == 0 )
            continue;

        Border rootBorder = VisualTreeHelper.GetChild( item, 0 ) as Border;
        if( rootBorder == null )
            continue; 

        this.AnimateItem( item, rootBorder );
    }           
}
 
void AnimateItem( ListBoxItem item, Border rootBorder )
{
    // The default Left of a ListBoxItem's root Border's Padding
    // is 2, so the animation logic ensures that the Padding's Left
    // is always at 2 or the "slide distance".
    Thickness thickness;
    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 );
        else
            thickness = new Thickness( 2, 0, this.SlideDistance, 0 );
    }
    else
    {
       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 ListBoxItem’s default 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 Thickness’s 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.

License

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


Written By
Software Developer (Senior)
United States United States
Josh creates software, for iOS and Windows.

He works at Black Pixel as a Senior 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[^].

See his website Josh Smith Digital[^].

Comments and Discussions

 
BugReplace Line on the project Please Pin
Reynaldots2-Mar-13 7:40
Reynaldots2-Mar-13 7:40 
GeneralMouse Over Pin
shancse26-Oct-10 1:08
shancse26-Oct-10 1:08 
GeneralPerformance Pin
opticalmess18-Jan-10 16:18
opticalmess18-Jan-10 16:18 
QuestionMultiple selections Pin
Felix Fennell28-Dec-09 2:34
Felix Fennell28-Dec-09 2:34 
GeneralNice Pin
Y.Yanavichus13-Apr-09 9:50
Y.Yanavichus13-Apr-09 9:50 
QuestionDisable Slide Duration Pin
craig2203331-Jul-08 5:00
craig2203331-Jul-08 5:00 
AnswerRe: Disable Slide Duration Pin
Josh Smith31-Jul-08 5:05
Josh Smith31-Jul-08 5:05 
Questionhow to manage a 3D listboxitem on a 3D listbox plane Pin
Brototy7-Jun-07 20:55
Brototy7-Jun-07 20:55 
AnswerRe: how to manage a 3D listboxitem on a 3D listbox plane Pin
Josh Smith8-Jun-07 2:44
Josh Smith8-Jun-07 2:44 
QuestionVery nice, but how to make it "resizable"? Pin
Nicola Tufarelli3-Apr-07 23:59
Nicola Tufarelli3-Apr-07 23:59 
AnswerRe: Very nice, but how to make it "resizable"? Pin
Josh Smith4-Apr-07 2:10
Josh Smith4-Apr-07 2:10 
GeneralDisable highlighting Pin
AdamGlowka6-Feb-07 17:52
AdamGlowka6-Feb-07 17:52 
GeneralRe: Disable highlighting Pin
AdamGlowka6-Feb-07 18:43
AdamGlowka6-Feb-07 18:43 
GeneralRe: Disable highlighting Pin
Josh Smith7-Feb-07 11:29
Josh Smith7-Feb-07 11:29 
GeneralRe: Disable highlighting Pin
tjordans31-Mar-08 5:04
tjordans31-Mar-08 5:04 
GeneralVery Nice Pin
Paul Conrad17-Nov-06 11:38
professionalPaul Conrad17-Nov-06 11:38 
GeneralRe: Very Nice Pin
Josh Smith17-Nov-06 11:48
Josh Smith17-Nov-06 11:48 
Thanks a lot! Smile | :)

:josh:
My WPF Blog[^]

GeneralProblem with namespace Pin
Muhammad Nasir Jabbar21-Oct-06 20:38
Muhammad Nasir Jabbar21-Oct-06 20:38 
GeneralRe: Problem with namespace Pin
Josh Smith22-Oct-06 4:52
Josh Smith22-Oct-06 4:52 
GeneralRe: Problem with namespace Pin
Muhammad Nasir Jabbar25-Oct-06 19:51
Muhammad Nasir Jabbar25-Oct-06 19:51 
GeneralRe: Problem with namespace Pin
Josh Smith26-Oct-06 2:03
Josh Smith26-Oct-06 2:03 

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

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