Why doesn't ListView.ScrollIntoView ever work?

You're passing in the index when the method expects the item object. Try this to scroll to the selected item.

ActivityList.ScrollIntoView(ActivityList.SelectedItem);

If you want to scroll to the last item, you can use this

ActivityList.ScrollIntoView(ActivityList.Items[ActivityList.Items.Count - 1]);

It's got something to do with the internal list representation, namely, the items are not yet in place when you call the ScrollIntoView(). After many attempts, this is what I finally came up with and this seems to work: attach two handlers to every ListBox/ListView:

<ListBox x:Name="YourList" ... Loaded="YourList_Loaded" SelectionChanged="YourList_SelectionChanged">

and

void YourList_Loaded(object sender, RoutedEventArgs e) {
  if (YourList.SelectedItem != null)
    YourList.ScrollIntoView(YourList.SelectedItem);
}

void YourList_SelectionChanged(object sender, SelectionChangedEventArgs e) {
  if (YourList.SelectedItem != null)
    YourList.ScrollIntoView(YourList.SelectedItem);
}

The second handler you can't do without. You can't call ScrollIntoView() immediately after you set the selected item, it's not yet ready. You have to allow the list to inform you when it has actually changed the item. The first handler depends on the circumstances, if you have problems with the selection showing up after the initial loading of the list contents, you might need it, too.


The problem with ActivityList.ScrollIntoView(ActivityList.Items[ActivityList.Items.Count - 1]); and similiar "solutions", at least from what I'm experiencing, is that when the ListBox contains the same item more than once, it jumps to the first it finds, i.e. lowest index. So, it doesn't care about the index of the item you input, it just looks for that item and picks the first.

I haven't yet found a solution to this, but the approach I'm taking right now is to Insert instead of Add items. In the original posters case I think that would result in:

activities.Insert(0, new Activities()
        {
            Time = DateTime.Now,
            Message = message
        });

or possibly:

ActivityList.Items.Insert(0, new Activities()
        {
            Time = DateTime.Now,
            Message = message
        });

Which causes every new entry to be inserted in the top, and thus ScrollIntoView doesn't even need to be called.

Tags:

C#

.Net

Wpf

Xaml