diff --git a/src/Controls/src/Core/LegacyLayouts/Layout.cs b/src/Controls/src/Core/LegacyLayouts/Layout.cs index 0f3b6d0b0d7f..afe03d8e6acc 100644 --- a/src/Controls/src/Core/LegacyLayouts/Layout.cs +++ b/src/Controls/src/Core/LegacyLayouts/Layout.cs @@ -609,6 +609,11 @@ void OnInternalAdded(View view) { InvalidateLayout(); } + + if (UseLegacyMeasureInvalidatedBehaviorEnabled) + { + view.MeasureInvalidated += OnChildMeasureInvalidated; + } } void OnInternalRemoved(View view, int oldIndex) @@ -618,6 +623,11 @@ void OnInternalRemoved(View view, int oldIndex) { InvalidateLayout(); } + + if (UseLegacyMeasureInvalidatedBehaviorEnabled) + { + view.MeasureInvalidated -= OnChildMeasureInvalidated; + } } bool ShouldLayoutChildren() diff --git a/src/Controls/src/Core/Page/Page.cs b/src/Controls/src/Core/Page/Page.cs index 53b083d64504..541280c0ef0c 100644 --- a/src/Controls/src/Core/Page/Page.cs +++ b/src/Controls/src/Core/Page/Page.cs @@ -66,6 +66,7 @@ public partial class Page : VisualElement, ILayout, IPageController, IElementCon readonly Lazy> _platformConfigurationRegistry; + bool _allocatedFlag; Rect _containerArea; bool _containerAreaSet; @@ -542,6 +543,7 @@ protected override void OnParentSet() /// The height allocated to the page. protected override void OnSizeAllocated(double width, double height) { + _allocatedFlag = true; base.OnSizeAllocated(width, height); UpdateChildrenLayout(); } @@ -603,7 +605,12 @@ internal virtual void OnChildMeasureInvalidated(VisualElement child, Invalidatio } } + _allocatedFlag = false; InvalidateMeasureInternal(InvalidationTrigger.MeasureChanged); + if (!_allocatedFlag && Width >= 0 && Height >= 0 && UseLegacyMeasureInvalidatedBehaviorEnabled) + { + SizeAllocated(Width, Height); + } } internal void OnAppearing(Action action) @@ -705,6 +712,13 @@ void InternalChildrenOnCollectionChanged(object sender, NotifyCollectionChangedE for (var i = 0; i < e.OldItems.Count; i++) { var item = (Element)e.OldItems[i]; + + if (UseLegacyMeasureInvalidatedBehaviorEnabled && + item is VisualElement visual) + { + visual.MeasureInvalidated -= OnChildMeasureInvalidated; + } + RemoveLogicalChild(item); } } @@ -721,6 +735,12 @@ void InternalChildrenOnCollectionChanged(object sender, NotifyCollectionChangedE insertIndex = InternalChildren.IndexOf(item); } + if (UseLegacyMeasureInvalidatedBehaviorEnabled && + item is VisualElement visual) + { + visual.MeasureInvalidated += OnChildMeasureInvalidated; + } + InsertLogicalChild(insertIndex, item); if (item is VisualElement) diff --git a/src/Controls/src/Core/VisualElement/VisualElement.cs b/src/Controls/src/Core/VisualElement/VisualElement.cs index 24946eb7c3d5..e2b8797d1fb1 100644 --- a/src/Controls/src/Core/VisualElement/VisualElement.cs +++ b/src/Controls/src/Core/VisualElement/VisualElement.cs @@ -1345,6 +1345,13 @@ internal void InvokeFocusChangeRequested(FocusRequestArgs args) => FocusChangeRequested?.Invoke(this, args); internal bool HasFocusChangeRequestedEvent => FocusChangeRequested is not null; + // Reverts the behavior changed in https://github.com/dotnet/maui/pull/23052/. This unblock customers that + // rely on the previous behavior or that are affected by the event propagation being slow on deep control + // hierarchies. This can be removed once a better fix is in place, such as https://github.com/dotnet/maui/pull/24848 + // or https://github.com/dotnet/maui/pull/25291. + internal static bool UseLegacyMeasureInvalidatedBehaviorEnabled { get; } = + AppContext.TryGetSwitch("Microsoft.Maui.RuntimeFeature.UseLegacyMeasureInvalidatedBehavior", out var enabled) && enabled; + /// /// Invalidates the measure of an element. /// @@ -1375,7 +1382,10 @@ internal virtual void InvalidateMeasureInternal(InvalidationTrigger trigger) } MeasureInvalidated?.Invoke(this, new InvalidationEventArgs(trigger)); - (Parent as VisualElement)?.OnChildMeasureInvalidatedInternal(this, trigger); + if (!UseLegacyMeasureInvalidatedBehaviorEnabled) + { + (Parent as VisualElement)?.OnChildMeasureInvalidatedInternal(this, trigger); + } } internal virtual void OnChildMeasureInvalidatedInternal(VisualElement child, InvalidationTrigger trigger)