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());
}
}
}