views:

638

answers:

3

How to correctly resize scrollbar when underlying collection of a WPF ListView changes?

I have a WPF ListView bound to an observeable collection with several thousand items. When a large number of these are removed the view seems to only show the last item. When I move the position in the view with the thumbbar, the thumbbar resizes to reflect the new collection size. Is it possible to force the ListView and Scroll bar to synchronise when the collection changes?

A: 

Strange behaviour!!

I would try setting the binding context (Context) of the ListView to null, and then the same list again in order to refresh the bindings.

Martin Randall
Nope, that doesn't seem to work. I tried setting `MyListView.DataContext` to both `null` and a blank dataset.
Jared Harley
+1  A: 

I have found a work-around if anyone else has this problem.

The following code example shows the items source of the ListView bening changed on the first line. The following lines show the workaround which is just to scroll back to the first item.

this.ListViewResults.ItemsSource = this.itemsFiltered;

object firstItem = this.ListViewResults.Items.GetItemAt(0);

if(firstItem == null)
{
    return;
}

this.ListViewResults.ScrollIntoView(firstItem);
Thomas Bratt
This works perfectly! Set your datasource/itemssource, find the first row and scroll to it!
Jared Harley
Did you have the same problem? I could not find many instances where other people had seen this.
Thomas Bratt
A: 

I have a different workaround which requires subclassing ListView. It's a bit more work but the result is better than just scrolling to the first item. But you'll need to adapt the ListView template such that the ScrollViewer in the template has a name (here PART_ScrollViewer) or you use another way to get the ScrollViewer object.

public class BetterListView : ListView
{
    ScrollViewer sv;
    public override void OnApplyTemplate()
    {
        base.OnApplyTemplate();
       //Get the scrollviewer in the template (I adapted the ListView template such that the ScrollViewer has a name property)
       sv = (this.Template.FindName("PART_ScrollViewer", this)) as ScrollViewer;
    }

    protected override void OnItemsChanged(NotifyCollectionChangedEventArgs e)
    {
        base.OnItemsChanged(e);
        //Prevent the bug where the ListView doesn't scroll correctly when a lot of items are removed
        if (sv != null && e.Action == NotifyCollectionChangedAction.Remove)
        {
            sv.InvalidateScrollInfo();
        }
    }
}
J W