ListView ScrollViewer问题

    我认为您正在寻找的实际上 是一种ListView 将元素滚动到的顶部的方法。

  • ScrollViewer 我创建了一个扩展方法是滚动到内的特定元素 。

    首先 ScrollViewer ,我需要找到   ListView 此类项目的实际实例,或滚动到next ListViewItem 。

    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;
        }

猜你喜欢

转载自blog.csdn.net/qq_28368039/article/details/106570046