My question is for UWP but the solution might be the same in WPF so I tagged that as well.
I'm trying to implement this extension method in a custom GridView and ListView so that when a selection changes, the selected item will always smoothly animate into view.
The extension method works great. However obtaining the UIElement container to send it does not work so great.
ListView.Items is bound to a collection in a ViewModel. So ListView.Items are not UIElements, but rather data objects. I need the SelectedItem's corresponding UIElement container.
First I tried this:
void ListView_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
if (_scrollViewer != null && this.ItemsPanelRoot != null && this.Items.Count > 0)
{
var selectedListViewItem = this.ItemsPanelRoot.Children[this.SelectedIndex];
if (selectedListViewItem != null)
{
_scrollViewer.ScrollToElement(selectedListViewItem);
}
}
}
This works at first but is actually no good. The indices of 'ListView.ItemsPanelRoot.Children' eventually start to diverge from 'ListView.Items' as the layout is updated dynamically.
Then I tried this, which so far seems to work fine:
void ListView_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
if (_scrollViewer != null && this.Items.Count > 0)
{
var selectedListViewItem = this.ItemsPanelRoot.FindDescendants<ListViewItem>()
.Where(x => x.Content == this.SelectedItem).FirstOrDefault();
if (selectedListViewItem != null)
{
_scrollViewer.ScrollToElement(selectedListViewItem);
}
else
{
throw new Exception();
}
}
}
The problem is that it seems incredibly expensive to do that query each time and also unsafe because there's no assurance that the container is available yet. I feel (hope) I'm missing something and that there's a proper way to do this.
Note: 'FindDescendants' is an extension method from Windows UI Toolkit, does the same thing as VisualTreeHelper.