Reputation: 1241
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.
Upvotes: 0
Views: 819
Reputation: 128061
ItemsControls have an ItemContainerGenerator
property, which holds an ItemContainerGenerator object that you can use to get item containers for items and item indexes and the like.
E.g.
var container = listView.ItemContainerGenerator.ContainerFromItem(item);
In UWP, the ContainerFromItem
and similar methods are also directly available in the ItemsControl class, so that you could write
var container = listView.ContainerFromItem(item);
Upvotes: 1