我認爲您正在尋找的實際上 是一種ListView
將元素滾動到的頂部的方法。
ScrollViewer
我創建了一個擴展方法是滾動到內的特定元素 。首先
ScrollViewer
,我需要找到ListView
此類項目的實際實例,或滾動到nextListViewItem
。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; }
ScrollViewer
我創建了兩個擴展方法,以基於例如索引或鏈接對象滾動到某個項目。ListView
並 共享GridView
相同的基類ListViewBase
。這兩種擴展方法GridView
也適用。。更新
基本上,該方法首先找到渲染的項目,然後立即滾動。如果該項爲
null
,則表示已啓用虛擬化並且尚未實現該項。ScrollIntoViewAsync
打電話給我們首先實現該項目 。( 與ScrollIntoView
包裝內置 的基於任務的方法ChangeViewAsync
相同(提供了更簡潔的代碼))計算並存儲位置。現在您知道要滾動的位置了,您必須首先立即將項目滾動回到上一個位置(即無動畫),然後使用動畫滾動到所需的位置。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; } }
ScrollIntoView
您還可以對第二個參數使用新的重載,以使該項目與頂部邊緣對齊。但是,這不會導致以前的擴展方法中的平滑滾動過渡。MyListView?.ScrollIntoView(MyListView.Items[5], ScrollIntoViewAlignment.Leading);
-
二
ScrollIntoView使該項進入視圖,並且不會滾動到句點。
當您呼叫成員並位於顯示列表的底部時,該項向下滾動,直到您成爲顯示列表的最後一個成員。
當您呼叫成員並位於列表頂部時,該項目將向上滾動,直到您成爲列表的第一個成員。
如果我呼叫了一個成員並且當前顯示該成員,則根本不起作用。
-
三
Var sv = new ScrollViewerHelper().GetScrollViewer(listView); sv.UpdateLayout(); sv.ChangeView(0, sv.ExtentHeight, null);
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; }