public ViewportInfo GetRelativeTo(IFrameworkElement_EffectiveViewport element) { Rect effective = Effective, clip = Clip; if (element is UIElement uiElement && Reference is UIElement usuallyTheParentOfElement) { var parentToElement = UIElement.GetTransform(uiElement, usuallyTheParentOfElement).Inverse(); if (Effective.IsValid) { effective = parentToElement.Transform(Effective); } if (Clip.IsValid) { clip = parentToElement.Transform(Clip); } } // If the Reference or the element is not a UIElement (native), we don't have any RenderTransform, // and we assume that the 'element' is stretched in it's parent usually true except for ListView, // but we won't even try to support that case. return(new ViewportInfo(element, effective, clip)); }
/// <summary> /// Used by a parent element to propagate down the viewport change /// </summary> void IFrameworkElement_EffectiveViewport.OnParentViewportChanged( IFrameworkElement_EffectiveViewport parent, // We propagate the parent to avoid costly lookup Rect viewport, // Be aware tht it might be empty ([+∞,+∞,-∞,-∞]) if not clipped bool isInitial) // Indicates that this update is only intended to initiate the _parentViewport { 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 IS_NATIVE_ELEMENT // No RenderTransform on native elements var viewportInLocalCoordinates = viewport; #else var viewportInLocalCoordinates = !viewport.IsEmpty && parent is UIElement parentElt ? GetTransform(this, parentElt).Inverse().Transform(viewport) : viewport; #endif if (!isInitial && viewportInLocalCoordinates == _parentViewport) { return; } _parentViewport = viewportInLocalCoordinates; PropagateEffectiveViewportChange(isInitial); }
/// <summary> /// Used by a child of this element, in order to subscribe to viewport updates /// (so the OnParentViewportChanged will be invoked on this given child) /// </summary> IDisposable IFrameworkElement_EffectiveViewport.RequestViewportUpdates(IFrameworkElement_EffectiveViewport child) { global::System.Diagnostics.Debug.Assert(Uno.UI.Extensions.DependencyObjectExtensions.GetChildren(this).OfType <IFrameworkElement_EffectiveViewport>().Contains(child)); _childrenInterestedInViewportUpdates++; ReconfigureViewportPropagation(child); return(Disposable.Create(() => { _childrenInterestedInViewportUpdates--; ReconfigureViewportPropagation(); })); }
/// <summary> /// Make sure to request or disable effective viewport changes from the parent /// </summary> private void ReconfigureViewportPropagation(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(this); } else { // We are the root of the visual tree (maybe just temporarily), // we update the effective viewport in order to initialize the _parentViewport of children. PropagateEffectiveViewportChange(isInitial: true); } } else { TRACE_EFFECTIVE_VIEWPORT("New child requested viewport propagation which has already been enabled. Force updating all children."); // 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 slot = LayoutInformation.GetLayoutSlot(this); // a.k.a. the implicit viewport to use if none was defined by any parent (usually only few elements at the top of the tree) var parentViewport = GetParentViewport(); var viewport = GetEffectiveViewport(parentViewport, slot); child?.OnParentViewportChanged(this, viewport, isInitial: true); } } else { if (_parentViewportUpdatesSubscription != null) { TRACE_EFFECTIVE_VIEWPORT("Disabling effective viewport propagation."); _parentViewportUpdatesSubscription.Dispose(); _parentViewportUpdatesSubscription = null; _parentViewport = Rect.Empty; } } }
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); }
/// <summary> /// Used by a parent element to propagate down the viewport change /// </summary> void IFrameworkElement_EffectiveViewport.OnParentViewportChanged( IFrameworkElement_EffectiveViewport parent, // We propagate the parent to avoid costly lookup Rect viewport, // Be aware tht it might be empty ([+∞,+∞,-∞,-∞]) if not clipped bool isInitial) // Indicates that this update is only intended to initiate the _parentViewport { 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 !__IOS__ // cf. GetParentViewport viewport = ParentToLocalCoordinates(parent, viewport); #endif if (!isInitial && viewport == _parentViewport) { return; } _parentViewport = viewport; PropagateEffectiveViewportChange(isInitial); }
/// <summary> /// Make sure to request or disable effective viewport changes from the parent /// </summary> private void ReconfigureViewportPropagation(IFrameworkElement_EffectiveViewport child = null) { if (IsLoaded && IsEffectiveViewportEnabled) { if (_parentViewportUpdatesSubscription == null) { var parent = Parent; if (parent is IFrameworkElement_EffectiveViewport parentFwElt) { _parentViewportUpdatesSubscription = parentFwElt.RequestViewportUpdates(this); } else { // We are the root of the visual tree (maybe just temporarily), // we update the effective viewport in order to initialize the _parentViewport of children. PropagateEffectiveViewportChange(isInitial: true); } } else { // 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. child?.OnParentViewportChanged(this, GetEffectiveViewport(), isInitial: true); } } else { if (_parentViewportUpdatesSubscription != null) { _parentViewportUpdatesSubscription.Dispose(); _parentViewportUpdatesSubscription = null; _parentViewport = Rect.Empty; } } }
public ViewportInfo(IFrameworkElement_EffectiveViewport reference, Rect effective, Rect clip) { Reference = reference; Effective = effective; Clip = clip; }
public ViewportInfo(IFrameworkElement_EffectiveViewport reference, Rect viewport) { Reference = reference; Effective = Clip = viewport; }