Ejemplo n.º 1
0
        void SortElements(Rect visibleWindow)
        {
            // Sort in descending order (inVisibleWindow, phase)
            m_pendingElements.Sort((lhs, rhs) =>
            {
                var lhsBounds     = lhs.VirtInfo.ArrangeBounds;
                var lhsIntersects = SharedHelpers.DoRectsIntersect(lhsBounds, visibleWindow);
                var rhsBounds     = rhs.VirtInfo.ArrangeBounds;
                var rhsIntersects = SharedHelpers.DoRectsIntersect(rhsBounds, visibleWindow);

                if ((lhsIntersects && rhsIntersects) ||
                    (!lhsIntersects && !rhsIntersects))
                {
                    // Both are in the visible window or both are not
                    return(lhs.VirtInfo.Phase - rhs.VirtInfo.Phase);
                }
                else if (lhsIntersects)
                {
                    // Left is in visible window
                    return(-1);
                }
                else
                {
                    return(1);
                }
            });
        }
Ejemplo n.º 2
0
        void DoPhasedWorkCallback()
        {
            MarkCallbackRecieved();

            if (m_pendingElements.Count > 0 && !BuildTreeScheduler.ShouldYield())
            {
                var visibleWindow = m_owner.VisibleWindow;
                SortElements(visibleWindow);
                int currentIndex = m_pendingElements.Count - 1;
                do
                {
                    var info      = m_pendingElements[currentIndex];
                    var element   = info.Element;
                    var virtInfo  = info.VirtInfo;
                    var dataIndex = virtInfo.Index;

                    int currentPhase = virtInfo.Phase;
                    if (currentPhase > 0)
                    {
                        int nextPhase = VirtualizationInfo.PhaseReachedEnd;
                        virtInfo.DataTemplateComponent.ProcessBindings(virtInfo.Data, -1 /* item index unused */, currentPhase, out nextPhase);
                        ValidatePhaseOrdering(currentPhase, nextPhase);

                        var previousAvailableSize = LayoutInformation.GetAvailableSize(element);
                        element.Measure(previousAvailableSize);

                        if (nextPhase > 0)
                        {
                            virtInfo.Phase = nextPhase;
                            // If we are the first item or
                            // If the current items phase is higher than the next items phase, then move to the next item.
                            if (currentIndex == 0 ||
                                virtInfo.Phase > m_pendingElements[currentIndex - 1].VirtInfo.Phase)
                            {
                                currentIndex--;
                            }
                        }
                        else
                        {
                            m_pendingElements.RemoveAt(currentIndex);
                            currentIndex--;
                        }
                    }
                    else
                    {
                        throw new InvalidOperationException("Cleared element found in pending list which is not expected");
                    }

                    var pendingCount = (int)(m_pendingElements.Count);
                    if (currentIndex == -1)
                    {
                        // Reached the top, start from the bottom again
                        currentIndex = pendingCount - 1;
                    }
                    else if (currentIndex > -1 && currentIndex < pendingCount - 1)
                    {
                        // If the next element is oustide the visible window and there are elements in the visible window
                        // go back to the visible window.
                        bool nextItemIsVisible = SharedHelpers.DoRectsIntersect(visibleWindow, m_pendingElements[currentIndex].VirtInfo.ArrangeBounds);
                        if (!nextItemIsVisible)
                        {
                            bool haveVisibleItems = SharedHelpers.DoRectsIntersect(visibleWindow, m_pendingElements[pendingCount - 1].VirtInfo.ArrangeBounds);
                            if (haveVisibleItems)
                            {
                                currentIndex = pendingCount - 1;
                            }
                        }
                    }
                } while (m_pendingElements.Count > 0 && !BuildTreeScheduler.ShouldYield());
            }

            if (m_pendingElements.Count > 0)
            {
                RegisterForCallback();
            }
        }
Ejemplo n.º 3
0
    // BringIntoView functionality is ported from WinUI ScrollPresenter
    // https://github.com/microsoft/microsoft-ui-xaml/blob/main/dev/ScrollPresenter/ScrollPresenter.cpp
    // with partial modifications to match the ScrollViewer control behavior.

    protected override void OnBringIntoViewRequested(BringIntoViewRequestedEventArgs args)
    {
        base.OnBringIntoViewRequested(args);

        UIElement content = RealContent as UIElement;

        if (args.Handled ||
            args.TargetElement == this ||
            (args.TargetElement == content && content?.Visibility == Visibility.Collapsed) ||
            !SharedHelpers.IsAncestor(args.TargetElement, this, true /*checkVisibility*/))
        {
            // Ignore the request when:
            // - It was handled already.
            // - The target element is this ScrollPresenter itself. A parent scrollPresenter may fulfill the request instead then.
            // - The target element is effectively collapsed within the ScrollPresenter.
            return;
        }

        Rect   targetRect = new Rect();
        double targetZoomedHorizontalOffset = 0.0;
        double targetZoomedVerticalOffset   = 0.0;
        double appliedOffsetX = 0.0;
        double appliedOffsetY = 0.0;
        var    viewportWidth  = ViewportWidth;
        var    viewportHeight = ViewportHeight;
        var    zoomFactor     = Scroller.ZoomFactor;

        // Compute the target offsets based on the provided BringIntoViewRequestedEventArgs.
        ComputeBringIntoViewTargetOffsets(
            content,
            args,
            out targetZoomedHorizontalOffset,
            out targetZoomedVerticalOffset,
            out appliedOffsetX,
            out appliedOffsetY,
            out targetRect);

        // Do not include the applied offsets so that potential parent bring-into-view contributors ignore that shift.
        Rect nextTargetRect = new Rect(
            targetRect.X * zoomFactor - targetZoomedHorizontalOffset - appliedOffsetX,
            targetRect.Y * zoomFactor - targetZoomedVerticalOffset - appliedOffsetY,
            Math.Min(targetRect.Width * zoomFactor, viewportWidth),
            Math.Min(targetRect.Height * zoomFactor, viewportHeight));

        Rect viewportRect = new Rect(
            0.0f,
            0.0f,
            (float)viewportWidth,
            (float)viewportHeight);

        var verticalOffset         = Scroller.VerticalOffset;
        var horizontalOffset       = Scroller.HorizontalOffset;
        var zoomedVerticalOffset   = verticalOffset;
        var zoomedHorizontalOffset = horizontalOffset;

        if (targetZoomedHorizontalOffset != zoomedHorizontalOffset ||
            targetZoomedVerticalOffset != zoomedVerticalOffset)
        {
            Scroller.ChangeView(targetZoomedHorizontalOffset, targetZoomedVerticalOffset, zoomFactor, !args.AnimationDesired);
        }
        else
        {
            // No offset change was triggered because the target offsets are the same as the current ones. Mark the operation as completed immediately.
            //RaiseViewChangeCompleted(true /*isForScroll*/, ScrollPresenterViewChangeResult::Completed, offsetsChangeCorrelationId);
        }

        if (SharedHelpers.DoRectsIntersect(nextTargetRect, viewportRect))
        {
            // Next bring a portion of this ScrollPresenter into view.
            args.TargetRect       = nextTargetRect;
            args.TargetElement    = Scroller;
            args.HorizontalOffset = args.HorizontalOffset - appliedOffsetX;
            args.VerticalOffset   = args.VerticalOffset - appliedOffsetY;
        }
        else
        {
            // This ScrollPresenter did not even partially bring the TargetRect into its viewport.
            // Mark the operation as handled since no portion of this ScrollPresenter needs to be brought into view.
            args.Handled = true;
        }
    }