scrollintoview div alternative c# visual-studio xaml windows-10 uwp

c# - div - scrollintoview offset



Windows 10 ScrollIntoView() no se desplaza a los elementos en el medio de una vista de lista (3)

Tengo una vista de lista con 20 elementos. Quiero desplazar la vista de lista mediante programación.

ListView?.ScrollIntoView(ListView.Items[0])

desplazará la vista de lista al primer elemento.

ListView?.ScrollIntoView(ListView.Items.Count - 1)

desplazará la vista de lista al final de la página.

Sin embargo, no puedo usar la misma función para desplazar la vista de lista a un elemento en el medio.

Eg: ListView?.ScrollIntoView(ListView.Items[5])

debería desplazarse y llevarme al quinto elemento de la lista. Pero en cambio me está llevando al primer elemento de la lista.

¿Sería genial si este comportamiento se puede lograr con alguna solución?


Creo que lo que está buscando es un método para desplazar un elemento a la parte superior de ListView .

En esta publicación , creé un método de extensión que se desplaza a un elemento particular dentro de un ScrollViewer .

La idea es la misma en tu caso.

Primero debe encontrar la instancia de ScrollViewer dentro de su ListView , luego el elemento real para desplazarse, es decir, un ListViewItem .

Aquí hay un método de extensión para obtener el ScrollViewer .

public static ScrollViewer GetScrollViewer(this DependencyObject element) { if (element is ScrollViewer) { return (ScrollViewer)element; } for (int i = 0; i < VisualTreeHelper.GetChildrenCount(element); i++) { var child = VisualTreeHelper.GetChild(element, i); var result = GetScrollViewer(child); if (result == null) { continue; } else { return result; } } return null; }

Una vez que obtengo la instancia de ScrollViewer , he creado dos métodos de extensión más para desplazarse a un elemento en función de su índice u objeto adjunto, respectivamente. Dado que ListView y GridView están compartiendo la misma clase base ListViewBase . Estos dos métodos de extensión también deberían funcionar para GridView .

Actualizar

Básicamente, los métodos encontrarán primero el elemento, si ya está renderizado, luego desplácese hasta él de inmediato. Si el elemento es null , significa que la virtualización está activada y el elemento aún no se ha realizado. Entonces, para realizar primero el elemento, llame a ScrollIntoViewAsync (método basado en tareas para envolver el ScrollIntoView , igual que ChangeViewAsync , que ofrece un código mucho más limpio), calcule la posición y guárdelo. Como ahora conozco la posición a la que desplazarme, primero necesito desplazar el elemento hasta su posición anterior al instante (es decir, sin animación), y luego, finalmente, desplazarme a la posición deseada con animación.

public async static Task ScrollToIndex(this ListViewBase listViewBase, int index) { bool isVirtualizing = default(bool); double previousHorizontalOffset = default(double), previousVerticalOffset = default(double); // get the ScrollViewer withtin the ListView/GridView var scrollViewer = listViewBase.GetScrollViewer(); // get the SelectorItem to scroll to var selectorItem = listViewBase.ContainerFromIndex(index) as SelectorItem; // when it''s null, means virtualization is on and the item hasn''t been realized yet if (selectorItem == null) { isVirtualizing = true; previousHorizontalOffset = scrollViewer.HorizontalOffset; previousVerticalOffset = scrollViewer.VerticalOffset; // call task-based ScrollIntoViewAsync to realize the item await listViewBase.ScrollIntoViewAsync(listViewBase.Items[index]); // this time the item shouldn''t be null again selectorItem = (SelectorItem)listViewBase.ContainerFromIndex(index); } // calculate the position object in order to know how much to scroll to var transform = selectorItem.TransformToVisual((UIElement)scrollViewer.Content); var position = transform.TransformPoint(new Point(0, 0)); // when virtualized, scroll back to previous position without animation if (isVirtualizing) { await scrollViewer.ChangeViewAsync(previousHorizontalOffset, previousVerticalOffset, true); } // scroll to desired position with animation! scrollViewer.ChangeView(position.X, position.Y, null); } public async static Task ScrollToItem(this ListViewBase listViewBase, object item) { bool isVirtualizing = default(bool); double previousHorizontalOffset = default(double), previousVerticalOffset = default(double); // get the ScrollViewer withtin the ListView/GridView var scrollViewer = listViewBase.GetScrollViewer(); // get the SelectorItem to scroll to var selectorItem = listViewBase.ContainerFromItem(item) as SelectorItem; // when it''s null, means virtualization is on and the item hasn''t been realized yet if (selectorItem == null) { isVirtualizing = true; previousHorizontalOffset = scrollViewer.HorizontalOffset; previousVerticalOffset = scrollViewer.VerticalOffset; // call task-based ScrollIntoViewAsync to realize the item await listViewBase.ScrollIntoViewAsync(item); // this time the item shouldn''t be null again selectorItem = (SelectorItem)listViewBase.ContainerFromItem(item); } // calculate the position object in order to know how much to scroll to var transform = selectorItem.TransformToVisual((UIElement)scrollViewer.Content); var position = transform.TransformPoint(new Point(0, 0)); // when virtualized, scroll back to previous position without animation if (isVirtualizing) { await scrollViewer.ChangeViewAsync(previousHorizontalOffset, previousVerticalOffset, true); } // scroll to desired position with animation! scrollViewer.ChangeView(position.X, position.Y, null); } public static async Task ScrollIntoViewAsync(this ListViewBase listViewBase, object item) { var tcs = new TaskCompletionSource<object>(); var scrollViewer = listViewBase.GetScrollViewer(); EventHandler<ScrollViewerViewChangedEventArgs> viewChanged = (s, e) => tcs.TrySetResult(null); try { scrollViewer.ViewChanged += viewChanged; listViewBase.ScrollIntoView(item, ScrollIntoViewAlignment.Leading); await tcs.Task; } finally { scrollViewer.ViewChanged -= viewChanged; } } public static async Task ChangeViewAsync(this ScrollViewer scrollViewer, double? horizontalOffset, double? verticalOffset, bool disableAnimation) { var tcs = new TaskCompletionSource<object>(); EventHandler<ScrollViewerViewChangedEventArgs> viewChanged = (s, e) => tcs.TrySetResult(null); try { scrollViewer.ViewChanged += viewChanged; scrollViewer.ChangeView(horizontalOffset, verticalOffset, null, disableAnimation); await tcs.Task; } finally { scrollViewer.ViewChanged -= viewChanged; } }

Un enfoque más simple, pero sin animación.

También puede usar la nueva sobrecarga de ScrollIntoView especificando el segundo parámetro para asegurarse de que el elemento esté alineado en el borde superior; sin embargo, hacerlo no tiene la transición de desplazamiento suave en mis métodos de extensión anteriores.

MyListView?.ScrollIntoView(MyListView.Items[5], ScrollIntoViewAlignment.Leading);


Resuelvo esto como:

var sv = new ScrollViewerHelper().GetScrollViewer(listView); sv.UpdateLayout(); sv.ChangeView(0, sv.ExtentHeight, null);

Y el método GetScrollViewer:

public ScrollViewer GetScrollViewer(DependencyObject element) { if (element is ScrollViewer) { return (ScrollViewer)element; } for (int i = 0; i < VisualTreeHelper.GetChildrenCount(element); i++) { var child = VisualTreeHelper.GetChild(element, i); var result = GetScrollViewer(child); if (result == null) { continue; } else { return result; } } return null; }

créditos al dueño del código


ScrollIntoView solo trae el elemento a la vista, punto, no se desplaza a una fila.

Si lo llama a un miembro y está debajo de la parte inferior de la lista visible, se desplaza hacia abajo hasta que el elemento sea el último miembro de la lista visible.

Si lo llama a un miembro y está encima de la parte superior de la lista, se desplaza hacia arriba hasta que el elemento sea el primer miembro de la lista.

Si lo llama a un miembro y actualmente está visible, no funciona en absoluto.