From c4a5567090357c49d0b69634406d6cb3195cd625 Mon Sep 17 00:00:00 2001 From: Steven Kirk Date: Fri, 28 Apr 2023 12:32:20 +0200 Subject: [PATCH 1/2] Added failing test for #11161. --- .../Layout/LayoutManagerTests.cs | 33 +++++++++++++++++++ .../Layout/LayoutTestControl.cs | 32 ++++++++++++++---- 2 files changed, 59 insertions(+), 6 deletions(-) diff --git a/tests/Avalonia.Base.UnitTests/Layout/LayoutManagerTests.cs b/tests/Avalonia.Base.UnitTests/Layout/LayoutManagerTests.cs index 09f78c5a6c..45a6efdd4a 100644 --- a/tests/Avalonia.Base.UnitTests/Layout/LayoutManagerTests.cs +++ b/tests/Avalonia.Base.UnitTests/Layout/LayoutManagerTests.cs @@ -514,5 +514,38 @@ namespace Avalonia.Base.UnitTests.Layout Assert.True(parent.IsMeasureValid); Assert.True(parent.IsArrangeValid); } + + [Fact] + public void Grandparent_Can_Invalidate_Root_Measure_During_Arrange() + { + // Issue #11161. + var child = new LayoutTestControl(); + var parent = new LayoutTestControl { Child = child }; + var grandparent = new LayoutTestControl { Child = parent }; + var root = new LayoutTestRoot { Child = grandparent }; + + root.LayoutManager.ExecuteInitialLayoutPass(); + + grandparent.DoArrangeOverride = (_, s) => + { + root.InvalidateMeasure(); + return s; + }; + grandparent.CallBaseArrange = true; + + child.InvalidateMeasure(); + grandparent.InvalidateMeasure(); + + root.LayoutManager.ExecuteLayoutPass(); + + Assert.True(child.IsMeasureValid); + Assert.True(child.IsArrangeValid); + Assert.True(parent.IsMeasureValid); + Assert.True(parent.IsArrangeValid); + Assert.True(grandparent.IsMeasureValid); + Assert.True(grandparent.IsArrangeValid); + Assert.True(root.IsMeasureValid); + Assert.True(root.IsArrangeValid); + } } } diff --git a/tests/Avalonia.Base.UnitTests/Layout/LayoutTestControl.cs b/tests/Avalonia.Base.UnitTests/Layout/LayoutTestControl.cs index 62de81006e..d85c7ed9bc 100644 --- a/tests/Avalonia.Base.UnitTests/Layout/LayoutTestControl.cs +++ b/tests/Avalonia.Base.UnitTests/Layout/LayoutTestControl.cs @@ -10,21 +10,41 @@ namespace Avalonia.Base.UnitTests.Layout public bool Arranged { get; set; } public Func DoMeasureOverride { get; set; } public Func DoArrangeOverride { get; set; } + public bool CallBaseMeasure { get; set; } + public bool CallBaseArrange { get; set; } protected override Size MeasureOverride(Size availableSize) { Measured = true; - return DoMeasureOverride != null ? - DoMeasureOverride(this, availableSize) : - base.MeasureOverride(availableSize); + + if (DoMeasureOverride is not null) + { + var overrideResult = DoMeasureOverride(this, availableSize); + return CallBaseMeasure ? + base.MeasureOverride(overrideResult) : + overrideResult; + } + else + { + return base.MeasureOverride(availableSize); + } } protected override Size ArrangeOverride(Size finalSize) { Arranged = true; - return DoArrangeOverride != null ? - DoArrangeOverride(this, finalSize) : - base.ArrangeOverride(finalSize); + + if (DoArrangeOverride is not null) + { + var overrideResult = DoArrangeOverride(this, finalSize); + return CallBaseArrange ? + base.ArrangeOverride(overrideResult) : + overrideResult; + } + else + { + return base.ArrangeOverride(finalSize); + } } } } From a03b73a7347fe442e141ead2662328cf686f3eee Mon Sep 17 00:00:00 2001 From: Steven Kirk Date: Fri, 28 Apr 2023 13:02:37 +0200 Subject: [PATCH 2/2] Always add control in measure queue to arrange queue. And also removed the checks for `IsAttachedToVisualTree`: that's going to be checked in `Arrange` and `Measure`. Fixes #11161 --- src/Avalonia.Base/Layout/LayoutManager.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Avalonia.Base/Layout/LayoutManager.cs b/src/Avalonia.Base/Layout/LayoutManager.cs index 747ee1c082..f47738f2e4 100644 --- a/src/Avalonia.Base/Layout/LayoutManager.cs +++ b/src/Avalonia.Base/Layout/LayoutManager.cs @@ -249,10 +249,12 @@ namespace Avalonia.Layout { var control = _toMeasure.Dequeue(); - if (!control.IsMeasureValid && control.IsAttachedToVisualTree) + if (!control.IsMeasureValid) { Measure(control); } + + _toArrange.Enqueue(control); } } @@ -262,7 +264,7 @@ namespace Avalonia.Layout { var control = _toArrange.Dequeue(); - if (!control.IsArrangeValid && control.IsAttachedToVisualTree) + if (!control.IsArrangeValid) { Arrange(control); } @@ -297,8 +299,6 @@ namespace Avalonia.Layout { control.Measure(control.PreviousMeasure.Value); } - - _toArrange.Enqueue(control); } return true;