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

     

     

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章