From 5e9f3067ce9babca797cdd8e99bec665001be9e0 Mon Sep 17 00:00:00 2001 From: Steven Kirk Date: Wed, 16 Oct 2019 10:32:21 +0200 Subject: [PATCH 1/3] Fix off-by-N error in VisualNode.TrimChildren. And added unit test. --- .../Rendering/SceneGraph/VisualNode.cs | 2 +- .../Rendering/SceneGraph/VisualNodeTests.cs | 19 +++++++++++++++++++ 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/src/Avalonia.Visuals/Rendering/SceneGraph/VisualNode.cs b/src/Avalonia.Visuals/Rendering/SceneGraph/VisualNode.cs index f579bf0a62..d342f2eb2e 100644 --- a/src/Avalonia.Visuals/Rendering/SceneGraph/VisualNode.cs +++ b/src/Avalonia.Visuals/Rendering/SceneGraph/VisualNode.cs @@ -218,7 +218,7 @@ namespace Avalonia.Rendering.SceneGraph if (first < _children?.Count) { EnsureChildrenCreated(); - for (int i = first; i < _children.Count - first; i++) + for (int i = first; i < _children.Count; i++) { _children[i].Dispose(); } diff --git a/tests/Avalonia.Visuals.UnitTests/Rendering/SceneGraph/VisualNodeTests.cs b/tests/Avalonia.Visuals.UnitTests/Rendering/SceneGraph/VisualNodeTests.cs index 24ba2d1c48..3211c3397b 100644 --- a/tests/Avalonia.Visuals.UnitTests/Rendering/SceneGraph/VisualNodeTests.cs +++ b/tests/Avalonia.Visuals.UnitTests/Rendering/SceneGraph/VisualNodeTests.cs @@ -101,5 +101,24 @@ namespace Avalonia.Visuals.UnitTests.Rendering.SceneGraph node.SortChildren(scene); } + + [Fact] + public void TrimChildren_Should_Work_Correctly() + { + var parent = new VisualNode(Mock.Of(), null); + var child1 = new VisualNode(Mock.Of(), null); + var child2 = new VisualNode(Mock.Of(), null); + var child3 = new VisualNode(Mock.Of(), null); + + parent.AddChild(child1); + parent.AddChild(child2); + parent.AddChild(child3); + parent.TrimChildren(2); + + Assert.Equal(2, parent.Children.Count); + Assert.False(child1.Disposed); + Assert.False(child2.Disposed); + Assert.True(child3.Disposed); + } } } From f6525de3c81b4754e9bc426684dae6647decdb94 Mon Sep 17 00:00:00 2001 From: Steven Kirk Date: Wed, 16 Oct 2019 10:18:24 +0200 Subject: [PATCH 2/3] Added failing test for #3115. --- .../Rendering/SceneGraph/SceneBuilderTests.cs | 52 +++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/tests/Avalonia.Visuals.UnitTests/Rendering/SceneGraph/SceneBuilderTests.cs b/tests/Avalonia.Visuals.UnitTests/Rendering/SceneGraph/SceneBuilderTests.cs index 13bcd27240..e226a61659 100644 --- a/tests/Avalonia.Visuals.UnitTests/Rendering/SceneGraph/SceneBuilderTests.cs +++ b/tests/Avalonia.Visuals.UnitTests/Rendering/SceneGraph/SceneBuilderTests.cs @@ -577,6 +577,58 @@ namespace Avalonia.Visuals.UnitTests.Rendering.SceneGraph } } + [Fact] + public void Should_Not_Dispose_Active_VisualNode_When_Control_Reparented_And_Child_Made_Invisible() + { + // Issue #3115 + using (UnitTestApplication.Start(TestServices.MockPlatformRenderInterface)) + { + StackPanel panel; + Border border1; + Border border2; + var tree = new TestRoot + { + Width = 100, + Height = 100, + Child = panel = new StackPanel + { + Children = + { + (border1 = new Border + { + Background = Brushes.Red, + }), + (border2 = new Border + { + Background = Brushes.Green, + }), + } + } + }; + + tree.Measure(Size.Infinity); + tree.Arrange(new Rect(tree.DesiredSize)); + + var scene = new Scene(tree); + var sceneBuilder = new SceneBuilder(); + sceneBuilder.UpdateAll(scene); + + var decorator = new Decorator(); + tree.Child = null; + decorator.Child = panel; + tree.Child = decorator; + border1.IsVisible = false; + + scene = scene.CloneScene(); + + var panelNode = (VisualNode)scene.FindNode(panel); + sceneBuilder.Update(scene, decorator); + + Assert.Equal(1, panelNode.Children.Count); + Assert.False(panelNode.Children[0].Disposed); + } + } + [Fact] public void Should_Update_ClipBounds_For_Negative_Margin() { From 534852af75bc83c3a4c1681f51cb13cba8ea7f70 Mon Sep 17 00:00:00 2001 From: Steven Kirk Date: Wed, 16 Oct 2019 10:53:24 +0200 Subject: [PATCH 3/3] Create VisualNode for invisible controls. If we don't do this, then a `VisualNode` can appear twice in its parent `ChildrenCollection` when an earlier sibling is made invisible. Fixes #3115 --- src/Avalonia.Visuals/Rendering/SceneGraph/SceneBuilder.cs | 4 ++++ .../Rendering/SceneGraph/SceneBuilderTests.cs | 3 ++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/src/Avalonia.Visuals/Rendering/SceneGraph/SceneBuilder.cs b/src/Avalonia.Visuals/Rendering/SceneGraph/SceneBuilder.cs index 161cbc099e..87c9ed0bae 100644 --- a/src/Avalonia.Visuals/Rendering/SceneGraph/SceneBuilder.cs +++ b/src/Avalonia.Visuals/Rendering/SceneGraph/SceneBuilder.cs @@ -240,6 +240,10 @@ namespace Avalonia.Rendering.SceneGraph } } } + else + { + contextImpl.BeginUpdate(node).Dispose(); + } } private void UpdateSize(Scene scene) diff --git a/tests/Avalonia.Visuals.UnitTests/Rendering/SceneGraph/SceneBuilderTests.cs b/tests/Avalonia.Visuals.UnitTests/Rendering/SceneGraph/SceneBuilderTests.cs index e226a61659..5fd14e9ea9 100644 --- a/tests/Avalonia.Visuals.UnitTests/Rendering/SceneGraph/SceneBuilderTests.cs +++ b/tests/Avalonia.Visuals.UnitTests/Rendering/SceneGraph/SceneBuilderTests.cs @@ -624,8 +624,9 @@ namespace Avalonia.Visuals.UnitTests.Rendering.SceneGraph var panelNode = (VisualNode)scene.FindNode(panel); sceneBuilder.Update(scene, decorator); - Assert.Equal(1, panelNode.Children.Count); + Assert.Equal(2, panelNode.Children.Count); Assert.False(panelNode.Children[0].Disposed); + Assert.False(panelNode.Children[1].Disposed); } }