0

In my application, I need to select the newly created document(note) when I go back to library. After library item is selected, the Library must be scrolled to the selected item.

My library's OnLoaded method:

private async void OnLoaded(object sender, RoutedEventArgs e)
{
   await this.ViewModel.InitializeAsync();

   // CollectionViewSource of my GridView being filled
   ViewModel.CollectionChanging = true;
   GroupInfoCVS.Source = ViewModel.GroupsCollection;
   ViewModel.CollectionChanging = false;

   // Loading Last selected item - THIS CHANGES SELECTION
   ViewModel.LoadLastSelection();
}

After I call the LoadLastSelection method, selection is changed successfuly (I've tested). This is the method that is called after that (in our GridView's extended control):

private void OnSelectionChanged(object sender, SelectionChangedEventArgs e)
{
    this.SelectedItemsCount = this.SelectedItems.Count;

    var newlySelectedItems = e.AddedItems;
    if (newlySelectedItems.Any())
    {
        var item = newlySelectedItems.Last();
        ScrollTo(item);
    }
}

private void ScrollTo(object item)
{
    UpdateLayout();
    var itemUI = (FrameworkElement)this.ContainerFromItem(item);

    if (itemUI != null)
    {
        _scrollViewer.UpdateLayout();
        _scrollViewer.ChangeView(null, itemUI.ActualOffset.Y - itemUI.ActualHeight, null, false);
    }
}

This also works for the most part. When itemUI is not null, the method scrolls successfully to the required item. The problems start when the items start to overflow the screen size. When items are completely hidden from the screen, they are virtualized. That means that ContainerFromItem returns null, so I can't take the offset properties. Keep in mind that this actually occurs before Library's OnLoaded method is finished.

Please, help me with some alternative to get such properties or other methods of scrolling, which will help me scroll successfully.

I've read a lot and tried using Dispatcher.RunAsync and ScrollIntoView methods, but I couldn't manage to produce any scrolling behavior. If you point me how to use them successfully, that would be a nice help too.

Here's what I've read (and tried):

ItemContainerGenerator.ContainerFromItem() returns null?

How to Know When a FrameworkElement Has Been Totally Rendered?

Is there a "All Children loaded" event in WPF

Let ListView scroll to selected item

Thanks in advance!

IMPORTANT: If you don't want to read all the conversation within the official answer, please read the solution in short here:

TemplatedControl's style had changed ScrollViewer's name from "ScrollViewer" to "LibraryScrollViewer" and that rendered ScrollIntoView method useless.

GeorgiG
  • 1,018
  • 1
  • 13
  • 29

1 Answers1

2

For GridView, the best way to achieve your needs is to call GridView.ScrollIntoView.

But you seem to have made similar attempts, and it does not to be successful, then the following points may help you:

1. Don't use GridView as a child element of ScrollViewer.

In your code, I see that you are calling the method of ScrollViewer.ChangeView to adjust the view scrolling, so it is speculated that you may put the GridView in the ScrollViewer, which is not recommended.

Because there is a ScrollViewer inside the GridView, and its ScrollIntoView method is to change the scroll area of the internal ScrollViewer. When there is a ScrollViewer outside, the ScrollViewer inside the GridView will lose the scrolling ability, thus making the ScrollIntoView method invalid.

2. Implement the Equals method of the data class.

If your data class is not a simple type (such as String, Int32, etc.), then implementing the Equals method of the data class will help the GridView to find the corresponding item.

Thanks.

Richard Zhang
  • 7,523
  • 1
  • 7
  • 13
  • Dear Richard, thanks. _scrollViewer is the ScrollViewer within the template of our GridView extension (NotesGridView). So in fact, ScrollViewer is a part of GridView, not the opposite. Thus far I had no problems doing equality checks. My main problem is that ScrollIntoView doesn't seem to work at all. – GeorgiG Jun 01 '20 at 09:08
  • 1
    Hello, as a comparison, you can use a normal `GridView` to display data, and call `ScrollIntoView` to see if it will take effect (I tried to create a simple demo that can scroll to the last item normally). If the normal `GridView` is effective, can you share the custom `GridView` control you created, the problem may be in this. – Richard Zhang Jun 01 '20 at 09:17
  • Dear Richard, you were right in a way we both didn't anticipate. We did have a templated control with a custom template. The main problem was the ScrollViewer - it is standardly named "ScrollViewer", but within our template it was renamed to "LibraryScrollViewer". That caused ScrollIntoView method to not work. Please, add a row into your answer to let people know to read through the comments below and I will mark it Answered. Otherwise I'd have to write the answer myself. – GeorgiG Nov 16 '20 at 15:18