Fixing jumpy ListBox scrolling in WP7 Mango

Update October 14, 2011: If you are using Buttons in your item templates this may cause some issues. See the comments at the bottom of the page for more information and a potential workaround.

A few days ago I tweeted about a ListBox scrolling issue I found with WP7 Mango when using item templates that have different heights. I first noticed this issue when using the Silverlight Toolkit’s LongListSelector control, but I found that it also applies to the standard ListBox control (which the Mango version of the Silverlight Toolkit uses internally to display data) whenever list items have different heights (e.g., wrapped text, list headers/footers, etc.).

In short, the issue is that after tapping/selecting an item in the list, scrolling becomes extremely jumpy. It’s a bit hard to describe — it’s not just a matter of poor performance, the list scroll position will actually jump up or down as you try to scroll through the list.

I found a relevant bug report on the SL Toolkit’s issue tracker here. At first I thought the issue was caused by selecting an item within the ListBox but I found that deselecting the item didn’t fix the scrolling behavior.

After doing some further testing I discovered that the issue was triggered whenever the ListBox (or a control displayed within the ListBox) gained focus. Setting focus to another control on the page seems to fix the issue completely.

To automatically remove focus from a ListBox or LongListSelector, you can hook into the GotFocus event:

In the event handler, simply focus another control. In this case, the PhoneApplicationPage itself:

private void myListBox_GotFocus(object sender, RoutedEventArgs e)
{
    this.Focus();
}

Subclassing ListBox/LongListSelector

A “cleaner” option is to create a class that inherits from ListBox/LongListSelector and override the OnGotFocus method. Whenever this method is called, you can attempt to search up the visual tree for an object that inherits from Control and set focus to that object.

This method is a bit more complicated, so I have included a sample project below. This project uses the TreeHelpers class that is included at the bottom of this file from the Silverlight Toolkit to get a FrameworkElement’s visual ancestors.

The sample project assumes you have the latest Silverlight Toolkit for Windows Phone installed.

5 thoughts on “Fixing jumpy ListBox scrolling in WP7 Mango”

  1. Nice job, but it doesn’t works together with a button in an itemtemplate. Even the visualstates are very short because of the focus change.

  2. Im not sure, but I think you can fix this by using the Scrollingstarted function to trigger the focus

  3. That’s true — if you use Buttons in your item templates this may cause some trouble. In my apps, I handle the Tap event from the ListBox/LongListSelector and then use the SelectedItem property to determine which item the user tapped.

    For item templates where tapping a different part of the template results in a different action, I set the Name property of one of the inner controls and then check the visual ancestors of e.OriginalSource. For example:

    var ancestors = e.OriginalSource.GetVisualAncestors();
    bool isPlayButton = ancestors.Any(a => (a is FrameworkElement) && ((FrameworkElement)a).Name == "PlayButton");
    

    If you’re using a LongListSelector, hooking into ScrollingStarted might be a better way to go. I haven’t tried it yet but it seems like that should work. Thanks for the comments!

  4. Thanks god I’m not the only one who noticed this issue. However I’m not able to fix it with the solution you provided.

    Any other suggestion? Actually, GotFocus event never fires, even if I have very simple templates! I’ve tried fixed item sizes of any kind, but jumps never stops.

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.