From fc7a83ee720dcbbf6590c7897404fba5b8331fde Mon Sep 17 00:00:00 2001 From: Steven Kirk Date: Sat, 2 Dec 2017 00:30:30 +0100 Subject: [PATCH] Fixed panel collection change actions. As suggested in #1286 --- .../Collections/IAvaloniaList.cs | 15 +++++ src/Avalonia.Controls/Panel.cs | 11 ++-- src/Avalonia.Visuals/Visual.cs | 13 ++++ .../Avalonia.Controls.UnitTests/PanelTests.cs | 63 ++++++++++++++++--- 4 files changed, 87 insertions(+), 15 deletions(-) diff --git a/src/Avalonia.Base/Collections/IAvaloniaList.cs b/src/Avalonia.Base/Collections/IAvaloniaList.cs index 0233cee7a9..48c36976a5 100644 --- a/src/Avalonia.Base/Collections/IAvaloniaList.cs +++ b/src/Avalonia.Base/Collections/IAvaloniaList.cs @@ -36,6 +36,21 @@ namespace Avalonia.Collections /// The items. void InsertRange(int index, IEnumerable items); + /// + /// Moves an item to a new index. + /// + /// The index of the item to move. + /// The index to move the item to. + void Move(int oldIndex, int newIndex); + + /// + /// Moves multiple items to a new index. + /// + /// The first index of the items to move. + /// The number of items to move. + /// The index to move the items to. + void MoveRange(int oldIndex, int count, int newIndex); + /// /// Removes multiple items from the collection. /// diff --git a/src/Avalonia.Controls/Panel.cs b/src/Avalonia.Controls/Panel.cs index 3272d3779b..6448f11491 100644 --- a/src/Avalonia.Controls/Panel.cs +++ b/src/Avalonia.Controls/Panel.cs @@ -115,6 +115,11 @@ namespace Avalonia.Controls VisualChildren.AddRange(e.NewItems.OfType()); break; + case NotifyCollectionChangedAction.Move: + LogicalChildren.MoveRange(e.OldStartingIndex, e.OldItems.Count, e.NewStartingIndex); + VisualChildren.MoveRange(e.OldStartingIndex, e.OldItems.Count, e.NewStartingIndex); + break; + case NotifyCollectionChangedAction.Remove: controls = e.OldItems.OfType().ToList(); LogicalChildren.RemoveAll(controls); @@ -132,11 +137,7 @@ namespace Avalonia.Controls break; case NotifyCollectionChangedAction.Reset: - controls = e.OldItems.OfType().ToList(); - LogicalChildren.Clear(); - VisualChildren.Clear(); - VisualChildren.AddRange(_children); - break; + throw new NotSupportedException(); } InvalidateMeasure(); diff --git a/src/Avalonia.Visuals/Visual.cs b/src/Avalonia.Visuals/Visual.cs index bc65d4f69f..3662fe50be 100644 --- a/src/Avalonia.Visuals/Visual.cs +++ b/src/Avalonia.Visuals/Visual.cs @@ -537,6 +537,19 @@ namespace Avalonia v.SetVisualParent(null); } + break; + + case NotifyCollectionChangedAction.Replace: + foreach (Visual v in e.OldItems) + { + v.SetVisualParent(null); + } + + foreach (Visual v in e.NewItems) + { + v.SetVisualParent(this); + } + break; } } diff --git a/tests/Avalonia.Controls.UnitTests/PanelTests.cs b/tests/Avalonia.Controls.UnitTests/PanelTests.cs index fb1ae3ba1a..29acdaa8d4 100644 --- a/tests/Avalonia.Controls.UnitTests/PanelTests.cs +++ b/tests/Avalonia.Controls.UnitTests/PanelTests.cs @@ -4,6 +4,7 @@ using System.Linq; using Avalonia.Collections; using Avalonia.LogicalTree; +using Avalonia.VisualTree; using Xunit; namespace Avalonia.Controls.UnitTests @@ -18,8 +19,9 @@ namespace Avalonia.Controls.UnitTests panel.Children.Add(child); - Assert.Equal(child.Parent, panel); - Assert.Equal(child.GetLogicalParent(), panel); + Assert.Same(child.Parent, panel); + Assert.Same(child.GetLogicalParent(), panel); + Assert.Same(child.GetVisualParent(), panel); } [Fact] @@ -45,6 +47,7 @@ namespace Avalonia.Controls.UnitTests Assert.Null(child.Parent); Assert.Null(child.GetLogicalParent()); + Assert.Null(child.GetVisualParent()); } [Fact] @@ -60,8 +63,10 @@ namespace Avalonia.Controls.UnitTests Assert.Null(child1.Parent); Assert.Null(child1.GetLogicalParent()); + Assert.Null(child1.GetVisualParent()); Assert.Null(child2.Parent); Assert.Null(child2.GetLogicalParent()); + Assert.Null(child2.GetVisualParent()); } [Fact] @@ -77,24 +82,32 @@ namespace Avalonia.Controls.UnitTests Assert.Null(child1.Parent); Assert.Null(child1.GetLogicalParent()); + Assert.Null(child1.GetVisualParent()); Assert.Null(child2.Parent); Assert.Null(child2.GetLogicalParent()); + Assert.Null(child2.GetVisualParent()); } [Fact] - public void Setting_Children_Should_Make_Controls_Appear_In_Panel_Children() + public void Replacing_Panel_Children_Should_Clear_And_Set_Control_Parent() { var panel = new Panel(); - var child = new Control(); + var child1 = new Control(); + var child2 = new Control(); - panel.Children = new Controls { child }; + panel.Children.Add(child1); + panel.Children[0] = child2; - Assert.Equal(new[] { child }, panel.Children); - Assert.Equal(new[] { child }, panel.GetLogicalChildren()); + Assert.Null(child1.Parent); + Assert.Null(child1.GetLogicalParent()); + Assert.Null(child1.GetVisualParent()); + Assert.Same(child2.Parent, panel); + Assert.Same(child2.GetLogicalParent(), panel); + Assert.Same(child2.GetVisualParent(), panel); } [Fact] - public void Child_Control_Should_Appear_In_Panel_Children() + public void Child_Control_Should_Appear_In_Panel_Logical_And_Visual_Children() { var panel = new Panel(); var child = new Control(); @@ -103,10 +116,11 @@ namespace Avalonia.Controls.UnitTests Assert.Equal(new[] { child }, panel.Children); Assert.Equal(new[] { child }, panel.GetLogicalChildren()); + Assert.Equal(new[] { child }, panel.GetVisualChildren()); } [Fact] - public void Removing_Child_Control_Should_Remove_From_Panel_Children() + public void Removing_Child_Control_Should_Remove_From_Panel_Logical_And_Visual_Children() { var panel = new Panel(); var child = new Control(); @@ -115,7 +129,36 @@ namespace Avalonia.Controls.UnitTests panel.Children.Remove(child); Assert.Equal(new Control[0], panel.Children); - Assert.Equal(new ILogical[0], panel.GetLogicalChildren()); + Assert.Empty(panel.GetLogicalChildren()); + Assert.Empty(panel.GetVisualChildren()); + } + + [Fact] + public void Moving_Panel_Children_Should_Reoder_Logical_And_Visual_Children() + { + var panel = new Panel(); + var child1 = new Control(); + var child2 = new Control(); + + panel.Children.Add(child1); + panel.Children.Add(child2); + panel.Children.Move(1, 0); + + Assert.Equal(new[] { child2, child1 }, panel.GetLogicalChildren()); + Assert.Equal(new[] { child2, child1 }, panel.GetVisualChildren()); + } + + [Fact] + public void Setting_Children_Should_Make_Controls_Appear_In_Logical_And_Visual_Children() + { + var panel = new Panel(); + var child = new Control(); + + panel.Children = new Controls { child }; + + Assert.Equal(new[] { child }, panel.Children); + Assert.Equal(new[] { child }, panel.GetLogicalChildren()); + Assert.Equal(new[] { child }, panel.GetVisualChildren()); } } }