3

I tried adding the following in a button click handler:

        ListView listView = MyListView;
        int lastItemIndex = listView.Items.Count - 1;
        listView.ScrollIntoView(listView.Items[lastItemIndex]);
        listView.UpdateLayout();

The button click is also associated with a command handler that adds an item to the ObservableCollection associated with the ListView.

The problem is that the button click handler is called before my command handler so it is too early. In the button click handler, the ListView does not yet see the updated ObservableCollection with the added item. What event or better yet, what can I do without changing the code behind to get the ListView to scroll to the end after my item is added to the ObservableCollection? I have looked but nothing yet in stackoverflow for answers. Thanks!

Buck
  • 599
  • 7
  • 20

2 Answers2

6

If you ItemSource is ObservableCollection, you can hook to CollectionChanged event in your Window/UserControl constructor and scroll last item into view whenever item gets added in a collection.

Assuming your underlying class is TesClass, this is how you will do it:

((INotifyCollectionChanged)listView.ItemsSource).CollectionChanged +=
     (s, e) =>
     {
         if (e.Action == 
             System.Collections.Specialized.NotifyCollectionChangedAction.Add)
         {
             listView.ScrollIntoView(listView.Items[listView.Items.Count - 1]);
         }
     };
Rohit Vats
  • 79,502
  • 12
  • 161
  • 185
  • 1
    Great and thanks! If convenient, do you know if it would be better to move this closer to the model classes? Wondering since is pretty domain/model specific. Ideas on how to do that with MVVM in mind? Thanks again. – Buck Jan 26 '14 at 11:13
  • How about using interface instead i.e. `INotifyCollectionChanged` (check update in answer)? This way you are abstracting out from accessing any model class from your view. Also moving this to ViewModel seems not right to me since we are doing view specific thing here (scrolling item into view). With interface in place i guess it's perfectly fine. You won't have to worry if underlying model class changes from TestClass to any other class. (of course as long as you are binding to a collection implementing INotifyCollectionChanged). – Rohit Vats Jan 26 '14 at 11:23
1

try this

VirtualizingStackPanel vsp = (VirtualizingStackPanel)typeof(ItemsControl).InvokeMember("_itemsHost", BindingFlags.Instance | BindingFlags.GetField | BindingFlags.NonPublic, null, _listView, null);

double scrollHeight = vsp.ScrollOwner.ScrollableHeight;
double offset = scrollHeight * lastItemIndex // itemIndex_ is index of the item which we want to show in the middle of the view

vsp.SetVerticalOffset(offset);

VirtualizingStackPanel

santosh singh
  • 27,666
  • 26
  • 83
  • 129