From c26173c4fe8e39b03a961666a94ebf74092f63af Mon Sep 17 00:00:00 2001 From: Steven Kirk Date: Fri, 1 Jul 2022 16:44:22 +0200 Subject: [PATCH 1/2] Added failing test for #7381. --- .../Rendering/SceneGraph/SceneBuilderTests.cs | 63 +++++++++++++++++++ 1 file changed, 63 insertions(+) diff --git a/tests/Avalonia.Base.UnitTests/Rendering/SceneGraph/SceneBuilderTests.cs b/tests/Avalonia.Base.UnitTests/Rendering/SceneGraph/SceneBuilderTests.cs index 879de9fca57..502575702a3 100644 --- a/tests/Avalonia.Base.UnitTests/Rendering/SceneGraph/SceneBuilderTests.cs +++ b/tests/Avalonia.Base.UnitTests/Rendering/SceneGraph/SceneBuilderTests.cs @@ -594,6 +594,69 @@ public void Should_Update_When_Control_Moved() } } + [Fact] + public void Should_Update_When_Control_Moved_Causing_Layout_Change() + { + using (UnitTestApplication.Start(TestServices.MockPlatformRenderInterface)) + { + Decorator moveFrom; + Decorator moveTo; + Canvas moveMe; + var tree = new TestRoot + { + Width = 100, + Height = 100, + Child = new DockPanel + { + Children = + { + (moveFrom = new Decorator + { + Child = moveMe = new Canvas + { + Width = 100, + Height = 100, + }, + }), + (moveTo = new Decorator()), + } + } + }; + + tree.Measure(Size.Infinity); + tree.Arrange(new Rect(tree.DesiredSize)); + + var scene = new Scene(tree); + var sceneBuilder = new SceneBuilder(); + sceneBuilder.UpdateAll(scene); + + var moveFromNode = (VisualNode)scene.FindNode(moveFrom); + var moveToNode = (VisualNode)scene.FindNode(moveTo); + + Assert.Equal(1, moveFromNode.Children.Count); + Assert.Same(moveMe, moveFromNode.Children[0].Visual); + Assert.Empty(moveToNode.Children); + + moveFrom.Child = null; + moveTo.Child = moveMe; + tree.LayoutManager.ExecuteLayoutPass(); + + scene = scene.CloneScene(); + moveFromNode = (VisualNode)scene.FindNode(moveFrom); + moveToNode = (VisualNode)scene.FindNode(moveTo); + + moveFromNode.SortChildren(scene); + moveToNode.SortChildren(scene); + sceneBuilder.Update(scene, moveFrom); + sceneBuilder.Update(scene, moveTo); + sceneBuilder.Update(scene, moveMe); + + Assert.Empty(moveFromNode.Children); + Assert.Equal(1, moveToNode.Children.Count); + Assert.Same(moveMe, moveToNode.Children[0].Visual); + } + } + [Fact] public void Should_Update_When_Control_Made_Invisible() { From cfe572f30bb40e749ecbb84cacc9477a35aa86e3 Mon Sep 17 00:00:00 2001 From: Steven Kirk Date: Fri, 1 Jul 2022 16:56:53 +0200 Subject: [PATCH 2/2] Remove node from parent when reparented. When a control was move from one parent container to another, and that move caused the new parent container to be laid out in a different position, a code path was taken which resulted in the `VisualNode` being present under both the old and new containers. Ensure that the node is removed from its old parent in this case. Fixes #7381 Fixes #6103 (probably) --- src/Avalonia.Base/Rendering/SceneGraph/SceneBuilder.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Avalonia.Base/Rendering/SceneGraph/SceneBuilder.cs b/src/Avalonia.Base/Rendering/SceneGraph/SceneBuilder.cs index 5dc426ab068..e4d5a1ca680 100644 --- a/src/Avalonia.Base/Rendering/SceneGraph/SceneBuilder.cs +++ b/src/Avalonia.Base/Rendering/SceneGraph/SceneBuilder.cs @@ -158,6 +158,7 @@ private static object GetOrCreateChildNode(Scene scene, IVisual child, VisualNod if (result != null && result.Parent != parent) { Deindex(scene, result); + ((VisualNode?)result.Parent)?.RemoveChild(result); result = null; }