|

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: <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: 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 )
{
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.
| You must Sign In to use this message board. |
|
| | Msgs 1 to 16 of 16 (Total in Forum: 16) (Refresh) | FirstPrevNext |
|
 |
|
|
Great work dude. I would like to mimic a dual listbox and when you select items and they are slide to the right to have them remain on the right side. Idealy to stack under each other, but that's outside the scope of this question.
Thanks, Craig
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
You could enable multi-select on the ListBox to achieve something similar to that, I think. See the SelectionMode property.
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
Hi, I have read a lot of your WPF articles and use them a lot. I am designing a 3D plane that will have a lot of data on it in the form of icons and text. I have created a control template for the list box. So my listbox is now a 3D plane that is rotated at the Z-axis. The problem is that the lisbox items are also appearing in the same rotated direction. I want the listbox items to stand up on the plane. Can you suggest me something abt this pretty soon.
Thanks, Brototy
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
 |
|
|
I know that setting to "Wrap" the TextWrapping property in the ListItem Datatemplate make the text wrap, but is it possible to bind its width property to the listbox width (minus SlideDistance), so that when the ListBox is resized also the list items are resized?
Many thanks for your code and articles...
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
You will have to bind the Width of the root element in the item template to the ActualWidth of the SlidingListBox. You'll need to use a MultiBinding so that you can pass in extra info like the SlideDistance and perhaps the Margin of the items.
:josh: My WPF Blog[ ^] Enjoy! Vote! Learn! Love! Save the whales! Eat raw diamonds! Do the Foxtrot in your tighty-whiteys! Start fires! Kill Martians!
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
Great control, thanks!
Is there any way to disable the focus highlight that Windows' applies to the selected list item? Selected items have a dark blue background (and list item text becomes white) until the focus is switched to another control (or window).
Ideally I'd like to see the selected item to just slide out with no colour changes at all. Possible?
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
So far one way I found is to use:
item.IsSelected = false;
towards the begining of the AnimateItem() function... Not sure if this approach may cause intermittent flicker on slower systems, so still keen to hear suggestions on how to change the 'Selected Background Color'.
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
You don't want to deselect the item, that will introduce other issues later on for you. What you should do is override the control template for ListBoxItem. The ListBoxItem control template has a trigger which sets the background color of the item to that standard "selected blue" when the ListBoxItem's IsSelected property is true. In your custom control template, do not add such a trigger.
If you want to see the default control template for a ListBoxItem, you can use the technique I blogged about here[^].
:josh: My WPF Blog[ ^] We are what we repeatedly do. Excellence then, is not an act, but a habit. - Aristotle
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
Josh Smith wrote: If you want to see the default control template for a ListBoxItem, you can use the technique I blogged about here[^].
Sorry but the site was not found. I have the same problem. When the ListBox lost the focus, the background color of the previous selected item changed again.
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
 |
|
|
 |
|
|
Thanks for writing a good article. I am facing a problem. I am getting error in Window1.xaml file at line "xmlns:jas="clr-namespace:WPF.JoshSmith.Controls"" it says that "Assembly was not found. The 'clr-namespace' URI refers to an assembly that is not referenced by the project". How can I solve this problem, Thanks in advance
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
Thanks, I'm glad you like the article. Is the problem you described a compiler error, or just a warning in the XAML editor? Does the project compile and run successfully? If not, what version of the .NET Framework 3.0 are you using?
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
Thanks for your response. I am using September CTP. I can't open form in design time. IT compiles successfully and runs application but it gives me a warning showing below, can you help me out this. Thanks in advance
"The element 'Grid' in namespace 'http://schemas.microsoft.com/winfx/2006/xaml/presentation' has invalid child element 'SlidingListBox' in namespace 'clr-namespace:WPF.JoshSmith.Controls'. List of possible elements expected: 'Grid.ShowGridLines, Grid.ColumnDefinitions, Grid.RowDefinitions, Grid.Background, Grid.IsItemsHost, Grid.Style, Grid.OverridesDefaultStyle, Grid.Triggers, Grid.Resources, Grid.DataContext, Grid.Language, Grid.Tag, Grid.InputScope, Grid.LayoutTransform, Grid.Width, Grid.MinWidth, Grid.MaxWidth, Grid.Height, Grid.MinHeight, Grid.MaxHeight, Grid.Margin, Grid.FocusVisualStyle, Grid.Cursor, Grid.ForceCursor, Grid.ToolTip, Grid.ContextMenu, Grid.InputBindings, Grid.CommandBindings, Grid.AllowDrop, Grid.RenderSize, Grid.RenderTransform, Grid.RenderTransformOrigin, Grid.Opacity, Grid.OpacityMask, Grid.BitmapEffect, Grid.BitmapEffectInput, Grid.ClipToBounds, Grid.Clip, Grid.SnapsToDevicePixels, Grid.IsEnabled, Grid.IsHitTestVisible, Grid.Focusable, sgUIElement, sgFrameworkElement, sgShape, Ellipse, Line, Path, Polygon, Polyline, Rectangle, sgPanel, Canvas, DockPanel, Grid, TabPanel, ToolBarOverflowPanel, sgStackPanel, ToolBarPanel, UniformGrid, sgVirtualizingPanel, VirtualizingStackPanel, WrapPanel, sgControl, sgC...."
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
As far as I know, there's nothing you can do to suppress that warning or have the designer display the Window. The XAML editor and WPF designer are still in their infancy, and the two problems you've described are well known issues that are a nuisance for everyone.
|
| Sign In·View Thread·PermaLink | 2.00/5 (1 vote) |
|
|
|
 |
|
|
General News Question Answer Joke Rant Admin
|