0

I need to Scroll NavigationView to its SelectedItem. In which I tried below methods one with TryMoveFocusAsync and another by tring to get ScrollViewer through parent of the SelectedItem from SelectionChanged event. But, the parent seems to be null.

Note: NavigationView doesn't have ScrollIntoView like ListView

1st Method

   private async void OnSelectionChanged(
         NavigationView sender, NavigationViewSelectionChangedEventArgs args)
   {
        if (args.SelectedItem is NavigationViewItem item)
        {
           FocusManager.TryFocusAsync(
                    sender.SelectedItem as DependencyObject,
                    FocusState.Pointer);
           ViewModel.NavigateTo(item.Name);
         }
         UpdateBackButton();
   }

2nd Method

   private async void OnSelectionChanged(
        NavigationView sender, NavigationViewSelectionChangedEventArgs args)

(args.SelectedItem as NavigationViewItem).Parent returns null.

Is there a way to scroll the NavigationViewMenuItem to its selected index?

Martin Zikmund
  • 38,440
  • 7
  • 70
  • 91
Vignesh
  • 1,824
  • 2
  • 10
  • 27

1 Answers1

2

Because the ScrollIntoView convenience method is not available outside of ListView it is a bit more work to get this done. First we need to write a helper method that finds the parent of a DependencyObject using the VisualTreeHelper:

private T FindParentOfType<T>(DependencyObject item)
{
    while (item != null)
    {
        item = VisualTreeHelper.GetParent(item);
        if (item is T expectedParent)
        {
            return expectedParent;
        }
    }
    return default;
}

Now using this, we first find the ScrollViewer (which should be a grand-parent of the NavigationViewItem):

var scrollViewer = FindParentOfType<ScrollViewer>(item);

We now need to find out the position of this menu item within the scroll viewer, which can be done using TransformToVisual and TransformPoint. Knowing this vertical location we can now scroll to it using ScrollViewer.ChangeView method:

if (scrollViewer != null)
{
    var transform = 
         item.TransformToVisual(scrollViewer)
             .TransformPoint(new Point(0,0));
    scrollViewer.ChangeView(null, transform.Y, null);
}
Martin Zikmund
  • 38,440
  • 7
  • 70
  • 91
  • Glad it helped, @Vignesh! Happy coding! – Martin Zikmund Nov 05 '19 at 09:40
  • Unfortunately, this doesn't work with longer lists where the system already virtualizes the non-visible parts of the list (longer here means above a few dozen items, not something really very long). Those items have to be realized first for the position to be valid. – Gábor Dec 24 '20 at 12:13
  • It should be possible to use `ListViewBase.ScrollIntoView`: https://learn.microsoft.com/en-us/uwp/api/windows.ui.xaml.controls.listviewbase.scrollintoview?view=winrt-19041 – Martin Zikmund Dec 24 '20 at 12:29
  • Hardly, considering that `NavigationView` isn't based on `ListViewBase`. Right now I'm trying to adapt https://stackoverflow.com/questions/32557216/windows-10-scrollintoview-is-not-scrolling-to-the-items-in-the-middle-of-a-lis and I'm mostly there but not yet. If it works, I'll post the solution. – Gábor Dec 24 '20 at 12:33
  • The old NavigationView template contains a NavigationViewListView control, which derives from ListView, so the method can be called on it. The new one in WinUI is based on ItemsRepeater, so there I am not sure how to do this yet – Martin Zikmund Dec 24 '20 at 18:42
  • Now that you mention it, this might be of some help: https://learn.microsoft.com/en-us/windows/uwp/design/controls-and-patterns/items-repeater#bringing-an-element-into-view – Gábor Dec 24 '20 at 23:14