From ccd7236346831665c98a1103b98c572cf77844b0 Mon Sep 17 00:00:00 2001 From: Steven Kirk Date: Tue, 11 Feb 2020 21:59:23 +0100 Subject: [PATCH 1/2] Added failing test for #3550. Calling `InvalidateMeasure` during `ExecuteInitialLayoutPass` causes invalid bounds/desired size. --- .../LayoutManagerTests.cs | 33 +++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/tests/Avalonia.Layout.UnitTests/LayoutManagerTests.cs b/tests/Avalonia.Layout.UnitTests/LayoutManagerTests.cs index 3f20c9a76a..0165b91844 100644 --- a/tests/Avalonia.Layout.UnitTests/LayoutManagerTests.cs +++ b/tests/Avalonia.Layout.UnitTests/LayoutManagerTests.cs @@ -374,5 +374,38 @@ namespace Avalonia.Layout.UnitTests Assert.True(control.Measured); Assert.True(control.IsMeasureValid); } + + [Fact] + public void Calling_ExecuteLayoutPass_From_ExecuteInitialLayoutPass_Does_Not_Break_Measure() + { + // Test for issue #3550. + var control = new LayoutTestControl(); + var root = new LayoutTestRoot { Child = control }; + var count = 0; + + root.LayoutManager.ExecuteInitialLayoutPass(root); + control.Measured = false; + + control.DoMeasureOverride = (l, s) => + { + if (count++ == 0) + { + control.InvalidateMeasure(); + root.LayoutManager.ExecuteLayoutPass(); + return new Size(100, 100); + } + else + { + return new Size(200, 200); + } + }; + + root.InvalidateMeasure(); + control.InvalidateMeasure(); + root.LayoutManager.ExecuteInitialLayoutPass(root); + + Assert.Equal(new Size(200, 200), control.Bounds.Size); + Assert.Equal(new Size(200, 200), control.DesiredSize); + } } } From d5fc004df0d149452e873040102f1e98cb929a2d Mon Sep 17 00:00:00 2001 From: Steven Kirk Date: Tue, 11 Feb 2020 21:59:51 +0100 Subject: [PATCH 2/2] Prevent reentrancy in ExecuteInitialLayoutPass. Fixes #3550. --- src/Avalonia.Layout/LayoutManager.cs | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/Avalonia.Layout/LayoutManager.cs b/src/Avalonia.Layout/LayoutManager.cs index 1792655a13..69a4406828 100644 --- a/src/Avalonia.Layout/LayoutManager.cs +++ b/src/Avalonia.Layout/LayoutManager.cs @@ -132,8 +132,16 @@ namespace Avalonia.Layout /// public void ExecuteInitialLayoutPass(ILayoutRoot root) { - Measure(root); - Arrange(root); + try + { + _running = true; + Measure(root); + Arrange(root); + } + finally + { + _running = false; + } // Running the initial layout pass may have caused some control to be invalidated // so run a full layout pass now (this usually due to scrollbars; its not known