Center a selected item in a scroll viewer

I am trying to center the selected item in a ListView inside a ScrollViewer and trying to calculate the vertical offset that I have to set the ScrollViewer relative to the ListView.

The following links set me to the correct track, but due to the limitations of the WinRT API, they were not able to use them:

The desired effect is as follows:

centered selected item in scrollviewer

This is an example installation in my XAML:

<ScrollViewer x:Name="MyScrollViewer"> <ListView x:Name="MyView" VerticalAlignment="Center" SelectionChanged="Selector_OnSelectionChanged"> <ListView.ItemTemplate> <DataTemplate> <Grid Width="80" Height="80" Margin="0"> <TextBlock Text="{Binding}" /> </Grid> </DataTemplate> </ListView.ItemTemplate> <ListView.Items> <x:String>1</x:String> <x:String>2</x:String> <x:String>3</x:String> <x:String>4</x:String> <x:String>5</x:String> <x:String>6</x:String> <x:String>7</x:String> <x:String>8</x:String> <x:String>9</x:String> </ListView.Items> </ListView> </ScrollViewer> 

Knowing the index of the selected item, how can I calculate the vertical offset that I can use in my method:

 private void Selector_OnSelectionChanged(object sender, SelectionChangedEventArgs e) { double maxVerticalOffset = MyScrollViewer.ExtentHeight - MyScrollViewer.ViewportHeight; int selectedItemIndex = MyView.SelectedIndex; double verticalOffset = ... MyScrollViewer.ChangeView(null, verticalOffset, null); } 
+2
source share
1 answer

Try ListView.ScrollIntoView() or ListView.MakeVisible first scroll the element container in the view and work on it may be virtualized from the user interface. Then use ListView.ItemContainerGenerator . ContainerFromIndex () to get the container of the item, and then VisualTreeHelper to get its position relative to the ScrollViewer . Then scroll the scrollviewer over the calculated offset.

* EDIT - An example of positioning logic:

Get VisualTreeHelperExtensions from the WinRT XAML Toolkit to access ScrollViewer easily using the GetFirstDescendantOfType() extension method, which transfers some calls to VisualTreeHelper .

Xaml

 <Page x:Class="ListViewItemCentering.MainPage" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="using:ListViewItemCentering" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d"> <Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"> <ListView x:Name="listView"> <ListView.ItemTemplate> <DataTemplate> <Border Width="400" Height="100"> <ContentControl Content="{Binding}" FontSize="48" Padding="20,10"/> </Border> </DataTemplate> </ListView.ItemTemplate> </ListView> <Button Content="Skip" Width="200" Height="100" HorizontalAlignment="Right" VerticalAlignment="Bottom" Click="ButtonBase_OnClick"/> </Grid> </Page> 

WITH#

 using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using Windows.Foundation; using Windows.UI.Xaml; using Windows.UI.Xaml.Controls; using WinRTXamlToolkit.Controls.Extensions; namespace ListViewItemCentering { /// <summary> /// An empty page that can be used on its own or navigated to within a Frame. /// </summary> public sealed partial class MainPage : Page { private Random random = new Random(); public MainPage() { this.InitializeComponent(); this.listView.ItemsSource = Enumerable.Range(1, 1000); this.listView.SelectionChanged += OnListViewSelectionChanged; } private async void OnListViewSelectionChanged(object sender, SelectionChangedEventArgs selectionChangedEventArgs) { if (listView.SelectedItem == null) { return; } var item = listView.SelectedItem; // Calculations relative to screen or ListView var listViewItem = (FrameworkElement)listView.ContainerFromItem(item); if (listViewItem == null) { listView.ScrollIntoView(item); } while (listViewItem == null) { await Task.Delay(1); // wait for scrolling to complete - it takes a moment listViewItem = (FrameworkElement)listView.ContainerFromItem(item); } var topLeft = listViewItem .TransformToVisual(listView) .TransformPoint(new Point()).Y; var lvih = listViewItem.ActualHeight; var lvh = listView.ActualHeight; var desiredTopLeft = (lvh - lvih) / 2.0; var desiredDelta = topLeft - desiredTopLeft; // Calculations relative to the ScrollViewer within the ListView var scrollViewer = listView.GetFirstDescendantOfType<ScrollViewer>(); var currentOffset = scrollViewer.VerticalOffset; var desiredOffset = currentOffset + desiredDelta; scrollViewer.ScrollToVerticalOffset(desiredOffset); // better yet if building for Windows 8.1 to make the scrolling smoother use: // scrollViewer.ChangeView(null, desiredOffset, null); } private async void ButtonBase_OnClick(object sender, RoutedEventArgs e) { this.listView.SelectedIndex = random.Next(0, ((IEnumerable<int>)this.listView.ItemsSource).Count()); } } } 
+6
source

Source: https://habr.com/ru/post/985847/


All Articles