diff --git a/src/Avalonia.Controls/Panel.cs b/src/Avalonia.Controls/Panel.cs
index fa18ee468c..eff6603727 100644
--- a/src/Avalonia.Controls/Panel.cs
+++ b/src/Avalonia.Controls/Panel.cs
@@ -1,13 +1,12 @@
using System;
-using System.Collections.Generic;
using System.Collections.Specialized;
using System.ComponentModel;
using System.Linq;
+using Avalonia.Controls.Presenters;
using Avalonia.LogicalTree;
using Avalonia.Media;
using Avalonia.Metadata;
using Avalonia.Reactive;
-using Avalonia.Styling;
namespace Avalonia.Controls
{
@@ -59,6 +58,11 @@ namespace Avalonia.Controls
set { SetValue(BackgroundProperty, value); }
}
+ ///
+ /// Gets whether the hosts the items created by an .
+ ///
+ public bool IsItemsHost { get; internal set; }
+
event EventHandler? IChildIndexProvider.ChildIndexChanged
{
add
@@ -129,24 +133,29 @@ namespace Avalonia.Controls
/// The event args.
protected virtual void ChildrenChanged(object? sender, NotifyCollectionChangedEventArgs e)
{
- List controls;
-
switch (e.Action)
{
case NotifyCollectionChangedAction.Add:
- controls = e.NewItems!.OfType().ToList();
- LogicalChildren.InsertRange(e.NewStartingIndex, controls);
+ if (!IsItemsHost)
+ {
+ LogicalChildren.InsertRange(e.NewStartingIndex, e.NewItems!.OfType().ToList());
+ }
VisualChildren.InsertRange(e.NewStartingIndex, 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);
+ if (!IsItemsHost)
+ {
+ 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);
+ if (!IsItemsHost)
+ {
+ LogicalChildren.RemoveAll(e.OldItems!.OfType().ToList());
+ }
VisualChildren.RemoveAll(e.OldItems!.OfType());
break;
@@ -155,7 +164,10 @@ namespace Avalonia.Controls
{
var index = i + e.OldStartingIndex;
var child = (Control)e.NewItems![i]!;
- LogicalChildren[index] = child;
+ if (!IsItemsHost)
+ {
+ LogicalChildren[index] = child;
+ }
VisualChildren[index] = child;
}
break;
@@ -200,6 +212,7 @@ namespace Avalonia.Controls
return child is Control control ? Children.IndexOf(control) : -1;
}
+ ///
public bool TryGetTotalCount(out int count)
{
count = Children.Count;
diff --git a/src/Avalonia.Controls/Presenters/ItemsPresenter.cs b/src/Avalonia.Controls/Presenters/ItemsPresenter.cs
index e8eaac7d17..0a762c438d 100644
--- a/src/Avalonia.Controls/Presenters/ItemsPresenter.cs
+++ b/src/Avalonia.Controls/Presenters/ItemsPresenter.cs
@@ -167,6 +167,7 @@ namespace Avalonia.Controls.Presenters
Panel = ItemsPanel.Build();
Panel.SetValue(TemplatedParentProperty, TemplatedParent);
+ Panel.IsItemsHost = true;
_scrollSnapPointsInfo = Panel as IScrollSnapPointsInfo;
LogicalChildren.Add(Panel);
VisualChildren.Add(Panel);
diff --git a/tests/Avalonia.Controls.UnitTests/ItemsControlTests.cs b/tests/Avalonia.Controls.UnitTests/ItemsControlTests.cs
index f074972cef..3aaf62f0bf 100644
--- a/tests/Avalonia.Controls.UnitTests/ItemsControlTests.cs
+++ b/tests/Avalonia.Controls.UnitTests/ItemsControlTests.cs
@@ -73,6 +73,19 @@ namespace Avalonia.Controls.UnitTests
Assert.Equal(target, target.Presenter.Panel.TemplatedParent);
}
+ [Fact]
+ public void Panel_Should_Have_ItemsHost_Set_To_True()
+ {
+ var target = new ItemsControl();
+
+ target.Template = GetTemplate();
+ target.Items = new[] { "Foo" };
+ target.ApplyTemplate();
+ target.Presenter!.ApplyTemplate();
+
+ Assert.True(target.Presenter.Panel!.IsItemsHost);
+ }
+
[Fact]
public void Container_Should_Have_TemplatedParent_Set_To_Null()
{
@@ -634,7 +647,7 @@ namespace Avalonia.Controls.UnitTests
target.ApplyTemplate();
target.Presenter.ApplyTemplate();
- var item = target.Presenter.Panel.LogicalChildren[0];
+ var item = target.LogicalChildren[0];
Assert.Null(NameScope.GetNameScope((TextBlock)item));
}
diff --git a/tests/Avalonia.Controls.UnitTests/PanelTests.cs b/tests/Avalonia.Controls.UnitTests/PanelTests.cs
index a31f0dd4c2..82f133d533 100644
--- a/tests/Avalonia.Controls.UnitTests/PanelTests.cs
+++ b/tests/Avalonia.Controls.UnitTests/PanelTests.cs
@@ -141,5 +141,20 @@ namespace Avalonia.Controls.UnitTests
var panel = new Panel();
Assert.Throws(() => panel.Children.Add(null!));
}
+
+ [Fact]
+ public void Adding_Control_To_Items_Host_Panel_Should_Not_Affect_Logical_Children()
+ {
+ var child = new Control();
+ var realParent = new ContentControl { Content = child };
+ var panel = new Panel { IsItemsHost = true };
+
+ panel.Children.Add(child);
+
+ Assert.Empty(panel.LogicalChildren);
+ Assert.Same(child.Parent, realParent);
+ Assert.Same(child.GetLogicalParent(), realParent);
+ Assert.Same(child.GetVisualParent(), panel);
+ }
}
}
diff --git a/tests/Avalonia.Controls.UnitTests/TabControlTests.cs b/tests/Avalonia.Controls.UnitTests/TabControlTests.cs
index 4c5397db60..0f72b2101a 100644
--- a/tests/Avalonia.Controls.UnitTests/TabControlTests.cs
+++ b/tests/Avalonia.Controls.UnitTests/TabControlTests.cs
@@ -327,7 +327,7 @@ namespace Avalonia.Controls.UnitTests
ApplyTemplate(target);
- var logicalChildren = target.ItemsPresenterPart.Panel.GetLogicalChildren();
+ var logicalChildren = target.GetLogicalChildren();
var result = logicalChildren
.OfType()
diff --git a/tests/Avalonia.Controls.UnitTests/TreeViewTests.cs b/tests/Avalonia.Controls.UnitTests/TreeViewTests.cs
index 1a9fb33b7e..2ca716fa8f 100644
--- a/tests/Avalonia.Controls.UnitTests/TreeViewTests.cs
+++ b/tests/Avalonia.Controls.UnitTests/TreeViewTests.cs
@@ -1178,7 +1178,7 @@ namespace Avalonia.Controls.UnitTests
target.ApplyTemplate();
target.Presenter.ApplyTemplate();
- var item = target.Presenter.Panel.LogicalChildren[0];
+ var item = target.LogicalChildren[0];
Assert.Null(NameScope.GetNameScope((TreeViewItem)item));
}