public static void ScrollIntoViewSmoothly(this ListViewBase listViewBase, object item, ScrollIntoViewAlignment alignment)
        {
            if (listViewBase == null)
            {
                throw new ArgumentNullException(nameof(listViewBase));
            }

            var scrollViewer = listViewBase.GetDescendantsOfType<ScrollViewer>().First();

            var originHorizontalOffset = scrollViewer.HorizontalOffset;
            var originVerticalOffset = scrollViewer.VerticalOffset;

            EventHandler<object> layoutUpdatedHandler = null;
            layoutUpdatedHandler = delegate
            {
                listViewBase.LayoutUpdated -= layoutUpdatedHandler;

                var targetHorizontalOffset = scrollViewer.HorizontalOffset;
                var targetVerticalOffset = scrollViewer.VerticalOffset;

                EventHandler<ScrollViewerViewChangedEventArgs> scrollHandler = null;
                scrollHandler = (sender, e) =>
                {
                    scrollViewer.ViewChanged -= scrollHandler;

                    scrollViewer.ChangeView(targetHorizontalOffset, targetVerticalOffset, null);
                };
                scrollViewer.ViewChanged += scrollHandler; ;

                scrollViewer.ChangeView(originHorizontalOffset, originVerticalOffset, null, true);
            };
            listViewBase.LayoutUpdated += layoutUpdatedHandler;

            listViewBase.ScrollIntoView(item, alignment);
        }
Example #2
0
        public static async Task ScrollIntoViewAsync(this ListViewBase listViewBase, object item, ScrollIntoViewAlignment alignment = ScrollIntoViewAlignment.Leading)
        {
            var tcs          = new TaskCompletionSource <object>();
            var scrollViewer = listViewBase.GetScrollViewer();

            EventHandler <object> layoutUpdated = (s1, e1) => tcs.TrySetResult(null);
            EventHandler <ScrollViewerViewChangedEventArgs> viewChanged = (s, e) =>
            {
                scrollViewer.LayoutUpdated += layoutUpdated;
                scrollViewer.UpdateLayout();
            };

            try
            {
                scrollViewer.ViewChanged += viewChanged;
                listViewBase.ScrollIntoView(item, alignment);
                await tcs.Task;
            }
            finally
            {
                scrollViewer.ViewChanged   -= viewChanged;
                scrollViewer.LayoutUpdated -= layoutUpdated;
            }
        }
        public static void ScrollIntoViewSmoothly(this ListViewBase listViewBase, object item, ScrollIntoViewAlignment alignment)
        {
            if (listViewBase == null)
            {
                throw new ArgumentException(nameof(ListViewBase));
            }

            // GetFirstDescendantOfType 是 WinRTXamlToolkit 中的扩展方法,
            // 寻找该控件在可视树上第一个符合类型的子元素。
            ScrollViewer scrollViewer = XamlHelper.FindChildOfType <ScrollViewer>(listViewBase);

            // 由于 ScrollViewer 肯定有,因此不做 null 检查判断了。

            // 记录初始位置,用于 ScrollIntoView 检测目标位置后复原。
            double originHorizontalOffset = scrollViewer.HorizontalOffset;
            double originVerticalOffset   = scrollViewer.VerticalOffset;

            EventHandler <object> layoutUpdatedHandler = null;

            layoutUpdatedHandler = delegate
            {
                listViewBase.LayoutUpdated -= layoutUpdatedHandler;

                // 获取目标位置。
                double targetHorizontalOffset = scrollViewer.HorizontalOffset;
                double targetVerticalOffset   = scrollViewer.VerticalOffset;

                EventHandler <ScrollViewerViewChangedEventArgs> scrollHandler = null;
                scrollHandler = delegate
                {
                    scrollViewer.ViewChanged -= scrollHandler;

                    // 最终目的,带平滑滚动效果滚动到 item。
                    scrollViewer.ChangeView(targetHorizontalOffset, targetVerticalOffset, null);
                };
                scrollViewer.ViewChanged += scrollHandler;

                // 复原位置,且不需要使用动画效果。
                scrollViewer.ChangeView(originHorizontalOffset, originVerticalOffset, null, true);
            };
            listViewBase.LayoutUpdated += layoutUpdatedHandler;

            // 跑腿。
            listViewBase.ScrollIntoView(item, alignment);
        }
Example #4
0
        public async Task GoToGroupAsync(int groupIndex, ScrollIntoViewAlignment scrollIntoViewAlignment = ScrollIntoViewAlignment.Leading)
        {
            if (groupCollection != null)
            {
                var gc = groupCollection;
                if (groupIndex < gc.GroupHeaders.Count && groupIndex >= 0 && !isGotoGrouping)
                {
                    isGotoGrouping = true;
                    //load more so that ScrollIntoViewAlignment.Leading can go to top
                    var loadcount = this.GetVisibleItemsCount() + 1;

                    progressRing.IsActive = true;
                    progressRing.Visibility = Visibility.Visible;
                    //make sure user don't do any other thing at the time.
                    this.IsHitTestVisible = false;
                    //await Task.Delay(3000);
                    while (gc.GroupHeaders[groupIndex].FirstIndex == -1)
                    {
                        if (gc.HasMoreItems)
                        {
                            await gc.LoadMoreItemsAsync(loadcount);
                        }
                        else
                        {
                            break;
                        }
                    }

                    if (gc.GroupHeaders[groupIndex].FirstIndex != -1)
                    {
                        //make sure there are enought items to go ScrollIntoViewAlignment.Leading
                        //this.count > (firstIndex + loadcount)
                        if (scrollIntoViewAlignment == ScrollIntoViewAlignment.Leading)
                        {
                            var more = this.Items.Count - (gc.GroupHeaders[groupIndex].FirstIndex + loadcount);
                            if (gc.HasMoreItems && more < 0)
                            {
                                await gc.LoadMoreItemsAsync((uint)Math.Abs(more));
                            }
                        }
                        progressRing.IsActive = false;
                        progressRing.Visibility = Visibility.Collapsed;
                        var groupFirstIndex = gc.GroupHeaders[groupIndex].FirstIndex;
                        ScrollIntoView(this.Items[groupFirstIndex], scrollIntoViewAlignment);

                        ListViewItem listViewItem = ContainerFromIndex(groupFirstIndex) as ListViewItem;
                        if (listViewItem != null)
                        {
                            GeneralTransform gt = listViewItem.TransformToVisual(this);
                            var rect = gt.TransformBounds(new Rect(0, 0, listViewItem.ActualWidth, listViewItem.ActualHeight));
                            //add delta,so that it does not look like suddenly
                            if (rect.Bottom < 0 || rect.Top > this.ActualHeight)
                            {

                            }
                            //already in viewport, maybe it will not change view 
                            else
                            {
                                this.IsHitTestVisible = true;
                                isGotoGrouping = false;
                            }
                        }
                    }
                    else
                    {
                        this.IsHitTestVisible = true;
                        isGotoGrouping = false;
                        progressRing.IsActive = false;
                        progressRing.Visibility = Visibility.Collapsed;
                    }

                }
            }
        }
Example #5
0
        public async Task GoToPreviousGroupAsync(ScrollIntoViewAlignment scrollIntoViewAlignment = ScrollIntoViewAlignment.Leading)
        {
            if (groupCollection != null)
            {
                var gc = groupCollection;

                var currentGroupIndex = GetCurrentVisibleGroupIndex();

                if (currentGroupIndex - 1 < 0)
                {
                    currentGroupIndex = gc.GroupHeaders.Count - 1;
                }
                else
                {
                    currentGroupIndex--;
                }
                await GoToGroupAsync(currentGroupIndex, scrollIntoViewAlignment);
            }
        }
Example #6
0
        public static async Task ScrollIntoViewAsync(this ListViewBase listViewBase, object item, ScrollIntoViewAlignment alignment, bool updateLayout)
        {
            var tcs          = new TaskCompletionSource <object>();
            var scrollViewer = listViewBase.GetScrollViewer();

            void layoutUpdated(object s1, object e1)
            {
                tcs.TrySetResult(null);
            }

            void viewChanged(object s, ScrollViewerViewChangedEventArgs e)
            {
                scrollViewer.LayoutUpdated += layoutUpdated;

                if (updateLayout)
                {
                    scrollViewer.UpdateLayout();
                }
            }

            try
            {
                scrollViewer.ViewChanged += viewChanged;
                listViewBase.ScrollIntoView(item, alignment);
                await tcs.Task;
            }
            finally
            {
                scrollViewer.ViewChanged   -= viewChanged;
                scrollViewer.LayoutUpdated -= layoutUpdated;
            }
        }
Example #7
0
        public async Task GoToGroupAsync(int groupIndex, ScrollIntoViewAlignment scrollIntoViewAlignment = ScrollIntoViewAlignment.Leading)
        {
            if (groupCollection != null)
            {
                var gc = groupCollection;
                if (groupIndex < gc.GroupHeaders.Count && groupIndex >= 0 && !isGotoGrouping)
                {
                    isGotoGrouping = true;
                    //load more so that ScrollIntoViewAlignment.Leading can go to top
                    var loadcount = this.GetVisibleItemsCount() + 1;

                    progressRing.IsActive   = true;
                    progressRing.Visibility = Visibility.Visible;
                    //make sure user don't do any other thing at the time.
                    this.IsHitTestVisible = false;
                    //await Task.Delay(3000);
                    while (gc.GroupHeaders[groupIndex].FirstIndex == -1)
                    {
                        if (gc.HasMoreItems)
                        {
                            await gc.LoadMoreItemsAsync(loadcount);
                        }
                        else
                        {
                            break;
                        }
                    }

                    if (gc.GroupHeaders[groupIndex].FirstIndex != -1)
                    {
                        //make sure there are enought items to go ScrollIntoViewAlignment.Leading
                        //this.count > (firstIndex + loadcount)
                        if (scrollIntoViewAlignment == ScrollIntoViewAlignment.Leading)
                        {
                            var more = this.Items.Count - (gc.GroupHeaders[groupIndex].FirstIndex + loadcount);
                            if (gc.HasMoreItems && more < 0)
                            {
                                await gc.LoadMoreItemsAsync((uint)Math.Abs(more));
                            }
                        }
                        progressRing.IsActive   = false;
                        progressRing.Visibility = Visibility.Collapsed;
                        var groupFirstIndex = gc.GroupHeaders[groupIndex].FirstIndex;
                        ScrollIntoView(this.Items[groupFirstIndex], scrollIntoViewAlignment);
                        //already in viewport, maybe it will not change view
                        if (groupDic.ContainsKey(gc.GroupHeaders[groupIndex]) && groupDic[gc.GroupHeaders[groupIndex]].Visibility == Visibility.Visible)
                        {
                            this.IsHitTestVisible = true;
                            isGotoGrouping        = false;
                        }
                    }
                    else
                    {
                        this.IsHitTestVisible   = true;
                        isGotoGrouping          = false;
                        progressRing.IsActive   = false;
                        progressRing.Visibility = Visibility.Collapsed;
                    }
                }
            }
        }
Example #8
0
        public async ValueTask ScrollIntoViewAsync(ElementReference element, ScrollIntoViewAlignment block, ScrollIntoViewAlignment inline, bool smooth = false)
        {
            var module = await _jsRuntime
                         .ImportOrGetModuleAsync(ModulePath, ModuleKey, _jsRefStore);

            await module.InvokeVoidAsync(
                "scrollIntoView",
                element,
                MapScrollIntoViewAlignment(block),
                MapScrollIntoViewAlignment(inline),
                smooth);
        }
Example #9
0
 public void ScrollIntoView(ElementReference element, ScrollIntoViewAlignment block, ScrollIntoViewAlignment inline, bool smooth = false)
 {
     _jsInProcessObjectRef !.InvokeVoid(
         "scrollIntoView",
         element,
         MapScrollIntoViewAlignment(block),
         MapScrollIntoViewAlignment(inline),
         smooth);
 }
Example #10
0
        public async Task ScrollToItem(object item, VerticalAlignment alignment, bool highlight, double?pixel = null, ScrollIntoViewAlignment direction = ScrollIntoViewAlignment.Leading, bool?disableAnimation = null)
        {
            var scrollViewer = ScrollingHost;

            if (scrollViewer == null)
            {
                Logs.Logger.Debug(Logs.Target.Chat, "ScrollingHost == null");

                return;
            }

            // We are going to try two times, as the first one seem to fail sometimes
            // leading the chat to the wrong scrolling position
            var iter = 2;

            var selectorItem = ContainerFromItem(item) as SelectorItem;

            while (selectorItem == null && iter > 0)
            {
                Logs.Logger.Debug(Logs.Target.Chat, string.Format("selectorItem == null, {0} try", iter + 1));

                // call task-based ScrollIntoViewAsync to realize the item
                await this.ScrollIntoViewAsync(item, direction);

                // this time the item shouldn't be null again
                selectorItem = ContainerFromItem(item) as SelectorItem;
                iter--;
            }

            if (selectorItem == null)
            {
                Logs.Logger.Debug(Logs.Target.Chat, "selectorItem == null, abort");
                return;
            }

            // 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));

            // If position is negative layout should still happen,
            // Lets wait for it.
            if (position.Y < 0)
            {
                Logs.Logger.Debug(Logs.Target.Chat, "position.Y is negative, let's wait for layout");

                // call task-based ScrollIntoViewAsync to realize the item
                await this.ScrollIntoViewAsync(item, direction);

                // this time the item shouldn't be null again
                selectorItem = ContainerFromItem(item) as SelectorItem;

                if (selectorItem == null)
                {
                    Logs.Logger.Debug(Logs.Target.Chat, "selectorItem == null after layout, abort");
                    return;
                }

                transform = selectorItem.TransformToVisual((UIElement)scrollViewer.Content);
                position  = transform.TransformPoint(new Point(0, 0));
            }

            if (alignment == VerticalAlignment.Top)
            {
                if (pixel is double adjust)
                {
                    position.Y -= adjust;
                }
            }
            else if (alignment == VerticalAlignment.Center)
            {
                if (selectorItem.ActualHeight < ActualHeight - 48)
                {
                    position.Y -= (ActualHeight - selectorItem.ActualHeight) / 2d;
                }
                else
                {
                    position.Y -= 48 + 4;
                }
            }
            else if (alignment == VerticalAlignment.Bottom)
            {
                position.Y -= ActualHeight - selectorItem.ActualHeight;

                if (pixel is double adjust)
                {
                    position.Y += adjust;
                }
            }

            if (highlight)
            {
                var bubble = selectorItem.Descendants <MessageBubble>().FirstOrDefault() as MessageBubble;
                if (bubble != null)
                {
                    bubble.Highlight();
                }
            }

            // scroll to desired position with animation!
            await scrollViewer.ChangeViewAsync(null, position.Y, disableAnimation ?? alignment != VerticalAlignment.Center);

            //scrollViewer.ChangeView(null, position.Y, null, disableAnimation ?? alignment != VerticalAlignment.Center);
        }
Example #11
0
        public async Task GoToGroupAsync(int groupIndex, ScrollIntoViewAlignment scrollIntoViewAlignment = ScrollIntoViewAlignment.Leading)
        {
            if (groupCollection != null)
            {
                var gc = groupCollection;
                if (groupIndex < gc.GroupHeaders.Count && groupIndex >= 0 && !isGotoGrouping)
                {
                    isGotoGrouping = true;
                    //load more so that ScrollIntoViewAlignment.Leading can go to top
                    var loadcount = this.GetVisibleItemsCount() + 1;

                    progressRing.IsActive = true;
                    progressRing.Visibility = Visibility.Visible;
                    //make sure user don't do any other thing at the time.
                    this.IsHitTestVisible = false;
                    //await Task.Delay(3000);
                    while (gc.GroupHeaders[groupIndex].FirstIndex == -1)
                    {
                        if (gc.HasMoreItems)
                        {
                            await gc.LoadMoreItemsAsync(loadcount);
                        }
                        else
                        {
                            break;
                        }
                    }

                    if (gc.GroupHeaders[groupIndex].FirstIndex != -1)
                    {
                        //make sure there are enought items to go ScrollIntoViewAlignment.Leading
                        //this.count > (firstIndex + loadcount)
                        if (scrollIntoViewAlignment == ScrollIntoViewAlignment.Leading)
                        {
                            var more = this.Items.Count - (gc.GroupHeaders[groupIndex].FirstIndex + loadcount);
                            if (gc.HasMoreItems && more < 0)
                            {
                                await gc.LoadMoreItemsAsync((uint)Math.Abs(more));
                            }
                        }
                        progressRing.IsActive = false;
                        progressRing.Visibility = Visibility.Collapsed;
                        var groupFirstIndex = gc.GroupHeaders[groupIndex].FirstIndex;
                        ScrollIntoView(this.Items[groupFirstIndex], scrollIntoViewAlignment);
                        //already in viewport, maybe it will not change view 
                        if (groupDic.ContainsKey(gc.GroupHeaders[groupIndex]) && groupDic[gc.GroupHeaders[groupIndex]].Visibility == Visibility.Visible)
                        {
                            this.IsHitTestVisible = true;
                            isGotoGrouping = false;
                        }
                    }
                    else
                    {
                        this.IsHitTestVisible = true;
                        isGotoGrouping = false;
                        progressRing.IsActive = false;
                        progressRing.Visibility = Visibility.Collapsed;
                    }

                }
            }
        }