Ejemplo n.º 1
0
        private void ReconfigureViewportPropagation(bool isInternal = false, IFrameworkElement_EffectiveViewport?child = null)
        {
            if (IsLoaded && IsEffectiveViewportEnabled)
            {
                if (_parentViewportUpdatesSubscription == null)
                {
                    TRACE_EFFECTIVE_VIEWPORT("Enabling effective viewport propagation.");

                    var parent = this.GetVisualTreeParent();
                    if (parent is IFrameworkElement_EffectiveViewport parentFwElt)
                    {
                        _parentViewportUpdatesSubscription = parentFwElt.RequestViewportUpdates(isInternal, this);
                    }
                    else
                    {
                        global::System.Diagnostics.Debug.Assert(IsVisualTreeRoot);

                        // We are the root of the visual tree, we update the effective viewport
                        // in order to initialize the _parentViewport of children.
                        PropagateEffectiveViewportChange(isInitial: true, isInternal: isInternal);
                    }
                }
                else if (child != null)
                {
                    TRACE_EFFECTIVE_VIEWPORT("New child requested viewport propagation which has already been enabled, forwarding current viewport to it.");

                    // We are already subscribed, the parent won't send any update (and our _parentViewport is expected to be up-to-date).
                    // But if this "reconfigure" was made for a new child (child != null), we have to initialize its own _parentViewport.

                    var parentViewport = GetParentViewport();
                    var viewport       = GetEffectiveViewport(parentViewport);

                    child.OnParentViewportChanged(isInitial: true, isInternal: true, this, viewport);
                }
            }
            else
            {
#if CHECK_LAYOUTED
                if (!IsLoaded)
                {
                    _isLayouted = false;
                }
#endif

                if (_parentViewportUpdatesSubscription != null)
                {
                    TRACE_EFFECTIVE_VIEWPORT("Disabling effective viewport propagation.");

                    _parentViewportUpdatesSubscription.Dispose();
                    _parentViewportUpdatesSubscription = null;

                    _parentViewport = ViewportInfo.Empty;
                }
            }
        }
Ejemplo n.º 2
0
        private ViewportInfo GetEffectiveViewport(ViewportInfo parentViewport)
        {
            global::System.Diagnostics.Debug.Assert(parentViewport.Reference == this || parentViewport.Reference == null);

            if (IsVisualTreeRoot)
            {
                var slot = LayoutInformation.GetLayoutSlot(this);

                return(new ViewportInfo(this, slot, Rect.Infinite));
            }

            if (IsScrollPort)
            {
                var viewport = parentViewport.Clip;

                // Pseudo intersect:
                // A normal intersect would return `Empty` as soon as the `viewport` and the `scrollport` does not overlap,
                // but on UWP the viewport is `Empty` only if the `viewport` is below the `scrollport` (for vertical scroll).
                // It means for an item in a list which is not yet visible on load (while vertical offset is 0), its EffVP will be empty.
                // Then when you scroll, its effVP will be something like [slot.Width,10 @ slot.X,slot.Y] when its first top 10px becomes visible.
                // Then if you continue to scroll and the item goes above the 'scrollport', its effVP will be [slot.Width,slot.Height @ slot.X,slot.Y]
                // while a normal intersect would be `Empty` (which is logic as the item is no longer visible at all,
                // but it make sense to not request to not go back to empty so element won't unload its content when scrolling up)!
                // However, nested scroll host has to do a real intersect.

                if (viewport.Right <= 0 ||
                    viewport.Bottom <= 0)
                {
                    return(new ViewportInfo(this, Rect.Empty));
                }

                // The visible window of the SCP
                // TODO: We should constrains the clip only on axis on which we can scroll
                var scrollport = new Rect(
                    new Point(ScrollOffsets.X, ScrollOffsets.Y),
                    LayoutInformation.GetLayoutSlot(this).Size);

                if (viewport.IsInfinite)
                {
                    viewport = scrollport;
                }
                else
                {
                    viewport.Intersect(scrollport);
                }

                return(new ViewportInfo(this, viewport));
            }

            return(parentViewport);
        }
Ejemplo n.º 3
0
        void IFrameworkElement_EffectiveViewport.OnParentViewportChanged(
            bool isInitial,                             // Update is intended to initiate the _parentViewport and should be "public" only if not due to a new event listener while tree is live (e.g. load)
            bool isInternal,                            // Indicates that this update is due to a new event handler
            IFrameworkElement_EffectiveViewport parent, // We propagate the parent to avoid costly lookup
            ViewportInfo viewport)                      // The viewport of the parent, expressed in parent's coordinates
        {
            if (!IsEffectiveViewportEnabled)
            {
                // We do not keep the _parentViewport up-to-date if not needed.
                // It's expected to the root parent to update its children when propagation activated.
                return;
            }

            if (!isInitial && viewport == _parentViewport)
            {
                return;
            }

            _parentViewport = viewport;
            PropagateEffectiveViewportChange(isInitial, isInternal);
        }