xaml - custom - uwp listview template
Deje que ListView se desplace hasta el elemento seleccionado (2)
Tengo una aplicación WinRT / C # / XAML con una vista que tiene una vista de lista vertical de elementos. Dependiendo de la cantidad de elementos, ListView muestra una barra de desplazamiento vertical. Aquí está la definición XAML:
<UserControl.Resources>
<CollectionViewSource
x:Name="myViewSource"
Source="{Binding myViewModel.Items}" />
</UserControl.Resources>
...
<ListView
x:Name="myListView"
ItemsSource="{Binding Source={StaticResource myViewSource}}"
SelectedItem="{Binding SelectedItem, Mode=TwoWay}">
</ListView>
Ahora, cada vez que navego a esta vista, el elemento seleccionado de ListView se elige configurando la propiedad SelectedItem de datos en el modelo de vista desde el código subyacente ( OnNavigatedTo
). Mi problema: el ListView no se desplaza automáticamente a este elemento seleccionado. La barra de desplazamiento permanece en la parte superior de ListView y el usuario tiene que desplazarse manualmente para ver el elemento seleccionado.
Traté de ejecutar myListView.ScrollIntoView(MyViewModel.SelectedItem);
después de configurar SelectedItem en el código detrás (en OnNavigatedTo
), pero no funciona. La barra de desplazamiento permanece en la parte superior.
Soy consciente de este hilo en SO: Desplácese WinRT ListView a un grupo particular . Esto parece ser un problema similar. Pero cuando recorro el árbol visual de ListView manualmente o con el WinRT XAML Toolkit, no encuentra un ScrollViewer (en su lugar devuelve null).
Gracias a Filip noté que llamar a ScrollIntoView()
en OnNavigatedTo()
era demasiado temprano, porque el control ListView
aún no está cargado en este lugar.
La primera idea de solución era vincular el evento Loaded
de ListView:
myListView.Loaded += (s, e) =>
myListView.ScrollIntoView(MyViewModel.SelectedItem);
Lamentablemente, esto causa un desagradable efecto visual, donde los elementos ListView actuales se superponen con el elemento seleccionado durante partes de un segundo, antes de que todo se reordene bien.
La solución final que encontré es llamar a ScrollIntoView()
forma asíncrona a través del Dispatcher
de la vista:
myListView.Loaded += (s, e) => Dispatcher.RunAsync(CoreDispatcherPriority.Normal,
() => myListView.ScrollIntoView(MyViewModel.SelectedItem));
Con esta solución, el diseño funciona bien.
Tenía una necesidad similar y la resolví de una manera ligeramente diferente. Me suscribí al SelectionChangedEvent de ListView y realicé el desplazamiento dentro del controlador.
XAML:
<ListView x:Name="myListView" SelectionChanged="myListView_SelectionChanged" ...>
</ListView>
Código:
private void myListView_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
myListView.ScrollIntoView(myListView.SelectedItem);
}