Wednesday, December 15, 2010

WPF ListView – ScrollIntoView

Lately a colleague of mine had a requirement to add items to a ListView programmatically. After adding an item, the ListView was supposed to scroll automatically so that the newly item came into view. First attempts to use the ScrollIntoView method of the ListView failed. There was just no scrolling at all. So I decided to check things up and here are the results.
ListView uses an ItemContainerGenerator that generates the UI and the visual tree for the ListView and its items. Whenever you add an item to the ListView the generator recreates all the item container elements. It does this in an asynchronous way. Therefore if you add an item programmatically and call ScrollIntoView right afterwards the container items will not have been created at this time and that’s why you won’t see any changes in the UI.
The trick here is to subscribe to the StatusChanged event of the ItemContainerGenerator:

listView.ItemContainerGenerator.StatusChanged += new ItemContainerGenerator_StatusChanged;

In the event handler you can check if the current status of the generator is equal to GeneratorStatus.ContainersGenerated:

void ItemContainerGenerator_StatusChanged(object sender, EventArgs e)
{
    if(listView.ItemContainerGenerator.Status ==
GeneratorStatus.ContainersGenerated)
    {
        var info = listView.Items[listView.Items.Count - 1] as FileInfo;
        if (info == null)
            return;

        listView.ScrollIntoView(info);
    }
}

If this is the case, all items have been created and you can use the ScrollIntoView method. In the example application I used a list of FileInfo objects that were created by a background thread one after another. The parameter of the ScrollIntoView method is of type object and one might suggest passing a ListViewItem, but that won’t work. Just get an item from the Items collection of the ListView and pass it to the method and you will see that the ListView gets scrolled automatically. And don’t forget to unsubscribe from the StatusChanged event. Otherwise nobody will be able to scroll the ListView from the UI.

4 comments:

  1. This is great info!

    Your suggestion has resolved two cases myself and another colleague were having ScrollIntoView issues.

    There is a Microsoft Connect bug against the ListView control that is closely related to what you've described in your example.

    I hope you don't mind that I added a workaround to the Microsoft Connect Site and gave credit to you and the DotNet Experience.

    The link is here:
    https://connect.microsoft.com/VisualStudio/Feedback/details/767426#tabs

    And in case that link goes bad, search this phrase, "ScrollIntoView does NOT always scroll to newly added Item"

    Cheers,

    Greg

    ReplyDelete
  2. Really great post you nailed it!

    This looked like a simple issue but turned out to be major one.
    I was faced with exactly the same problem in my c++ Metro Store App implementation.
    I was looking for a suitable ListView event but couldn't find just the right one.
    Work's great thanks to your solution

    Many thanks (from Poland),

    Marcin


    ReplyDelete