diff --git a/src/Avalonia.Controls/Generators/IItemContainerGenerator.cs b/src/Avalonia.Controls/Generators/IItemContainerGenerator.cs
index ba584e33b9..d139c95fd4 100644
--- a/src/Avalonia.Controls/Generators/IItemContainerGenerator.cs
+++ b/src/Avalonia.Controls/Generators/IItemContainerGenerator.cs
@@ -22,6 +22,11 @@ namespace Avalonia.Controls.Generators
///
IDataTemplate ItemTemplate { get; set; }
+ ///
+ /// Gets the ContainerType, or null if its an untyped ContainerGenerator.
+ ///
+ Type ContainerType { get; }
+
///
/// Signalled whenever new containers are materialized.
///
diff --git a/src/Avalonia.Controls/Generators/ItemContainerGenerator.cs b/src/Avalonia.Controls/Generators/ItemContainerGenerator.cs
index 4d65210002..882d2f4ddd 100644
--- a/src/Avalonia.Controls/Generators/ItemContainerGenerator.cs
+++ b/src/Avalonia.Controls/Generators/ItemContainerGenerator.cs
@@ -50,6 +50,9 @@ namespace Avalonia.Controls.Generators
///
public IControl Owner { get; }
+ ///
+ public virtual Type ContainerType => null;
+
///
public ItemContainerInfo Materialize(
int index,
diff --git a/src/Avalonia.Controls/Generators/ItemContainerGenerator`1.cs b/src/Avalonia.Controls/Generators/ItemContainerGenerator`1.cs
index 3aa2181cd4..259c524d59 100644
--- a/src/Avalonia.Controls/Generators/ItemContainerGenerator`1.cs
+++ b/src/Avalonia.Controls/Generators/ItemContainerGenerator`1.cs
@@ -34,6 +34,9 @@ namespace Avalonia.Controls.Generators
ContentTemplateProperty = contentTemplateProperty;
}
+ ///
+ public override Type ContainerType => typeof(T);
+
///
/// Gets the container's Content property.
///
diff --git a/src/Avalonia.Controls/ItemsControl.cs b/src/Avalonia.Controls/ItemsControl.cs
index 8f92cc43b7..5d12c9963f 100644
--- a/src/Avalonia.Controls/ItemsControl.cs
+++ b/src/Avalonia.Controls/ItemsControl.cs
@@ -4,7 +4,6 @@
using System.Collections;
using System.Collections.Generic;
using System.Collections.Specialized;
-using System.Diagnostics.CodeAnalysis;
using System.Linq;
using Avalonia.Collections;
using Avalonia.Controls.Generators;
@@ -226,19 +225,35 @@ namespace Avalonia.Controls
/// The details of the containers.
protected virtual void OnContainersMaterialized(ItemContainerEventArgs e)
{
- var toAdd = new List();
-
foreach (var container in e.Containers)
{
// If the item is its own container, then it will be added to the logical tree when
// it was added to the Items collection.
if (container.ContainerControl != null && container.ContainerControl != container.Item)
{
- toAdd.Add(container.ContainerControl);
+ if (ItemContainerGenerator.ContainerType == null)
+ {
+ var containerControl = container.ContainerControl as ContentPresenter;
+
+ if (containerControl != null)
+ {
+ ((ISetLogicalParent)containerControl).SetParent(this);
+ containerControl.SetValue(TemplatedParentProperty, null);
+
+ containerControl.UpdateChild();
+
+ if (containerControl.Child != null)
+ {
+ LogicalChildren.Add(containerControl.Child);
+ }
+ }
+ }
+ else
+ {
+ LogicalChildren.Add(container.ContainerControl);
+ }
}
}
-
- LogicalChildren.AddRange(toAdd);
}
///
@@ -248,19 +263,32 @@ namespace Avalonia.Controls
/// The details of the containers.
protected virtual void OnContainersDematerialized(ItemContainerEventArgs e)
{
- var toRemove = new List();
-
foreach (var container in e.Containers)
{
// If the item is its own container, then it will be removed from the logical tree
// when it is removed from the Items collection.
if (container?.ContainerControl != container?.Item)
{
- toRemove.Add(container.ContainerControl);
+ if (ItemContainerGenerator.ContainerType == null)
+ {
+ var containerControl = container.ContainerControl as ContentPresenter;
+
+ if (containerControl != null)
+ {
+ ((ISetLogicalParent)containerControl).SetParent(null);
+
+ if (containerControl.Child != null)
+ {
+ LogicalChildren.Remove(containerControl.Child);
+ }
+ }
+ }
+ else
+ {
+ LogicalChildren.Remove(container.ContainerControl);
+ }
}
}
-
- LogicalChildren.RemoveAll(toRemove);
}
///
diff --git a/tests/Avalonia.Controls.UnitTests/CarouselTests.cs b/tests/Avalonia.Controls.UnitTests/CarouselTests.cs
index 0e3c6f5953..e91ab02327 100644
--- a/tests/Avalonia.Controls.UnitTests/CarouselTests.cs
+++ b/tests/Avalonia.Controls.UnitTests/CarouselTests.cs
@@ -50,8 +50,9 @@ namespace Avalonia.Controls.UnitTests
Assert.Equal(1, target.GetLogicalChildren().Count());
var child = target.GetLogicalChildren().Single();
- Assert.IsType(child);
- Assert.Equal("Foo", ((ContentPresenter)child).Content);
+
+ Assert.IsType(child);
+ Assert.Equal("Foo", ((TextBlock)child).Text);
}
[Fact]
diff --git a/tests/Avalonia.Controls.UnitTests/ItemsControlTests.cs b/tests/Avalonia.Controls.UnitTests/ItemsControlTests.cs
index dcbc71b9a1..e88d1881e6 100644
--- a/tests/Avalonia.Controls.UnitTests/ItemsControlTests.cs
+++ b/tests/Avalonia.Controls.UnitTests/ItemsControlTests.cs
@@ -9,6 +9,8 @@ using Avalonia.Controls.Templates;
using Avalonia.LogicalTree;
using Avalonia.VisualTree;
using Xunit;
+using System.Collections.ObjectModel;
+using Avalonia.UnitTests;
namespace Avalonia.Controls.UnitTests
{
@@ -61,6 +63,32 @@ namespace Avalonia.Controls.UnitTests
Assert.Null(container.TemplatedParent);
}
+ [Fact]
+ public void Container_Child_Should_Have_LogicalParent_Set_To_Container()
+ {
+ using (UnitTestApplication.Start(TestServices.StyledWindow))
+ {
+ var root = new Window();
+ var target = new ItemsControl();
+
+ root.Content = target;
+
+ var templatedParent = new Button();
+ target.TemplatedParent = templatedParent;
+ target.Template = GetTemplate();
+
+ target.Items = new[] { "Foo" };
+
+ root.ApplyTemplate();
+ target.ApplyTemplate();
+ target.Presenter.ApplyTemplate();
+
+ var container = (ContentPresenter)target.Presenter.Panel.Children[0];
+
+ Assert.Equal(container, container.Child.Parent);
+ }
+ }
+
[Fact]
public void Control_Item_Should_Be_Logical_Child_Before_ApplyTemplate()
{
@@ -138,7 +166,7 @@ namespace Avalonia.Controls.UnitTests
}
[Fact]
- public void Adding_String_Item_Should_Make_ContentPresenter_Appear_In_LogicalChildren()
+ public void Adding_String_Item_Should_Make_TextBlock_Appear_In_LogicalChildren()
{
var target = new ItemsControl();
var child = new Control();
@@ -150,7 +178,7 @@ namespace Avalonia.Controls.UnitTests
var logical = (ILogical)target;
Assert.Equal(1, logical.LogicalChildren.Count);
- Assert.IsType(logical.LogicalChildren[0]);
+ Assert.IsType(logical.LogicalChildren[0]);
}
[Fact]
@@ -171,6 +199,7 @@ namespace Avalonia.Controls.UnitTests
Assert.Equal(new ILogical[0], target.GetLogicalChildren());
}
+
[Fact]
public void Setting_Items_Should_Fire_LogicalChildren_CollectionChanged()
{