Browse Source

Merge branch 'master' into magick

Steven Kirk 9 years ago
parent
commit
41fc010ef8

+ 5 - 0
src/Avalonia.Controls/Generators/IItemContainerGenerator.cs

@@ -22,6 +22,11 @@ namespace Avalonia.Controls.Generators
         /// </summary>
         IDataTemplate ItemTemplate { get; set; }
 
+        /// <summary>
+        /// Gets the ContainerType, or null if its an untyped ContainerGenerator.
+        /// </summary>
+        Type ContainerType { get; }
+
         /// <summary>
         /// Signalled whenever new containers are materialized.
         /// </summary>

+ 3 - 0
src/Avalonia.Controls/Generators/ItemContainerGenerator.cs

@@ -50,6 +50,9 @@ namespace Avalonia.Controls.Generators
         /// </summary>
         public IControl Owner { get; }
 
+        /// <inheritdoc/>
+        public virtual Type ContainerType => null;
+
         /// <inheritdoc/>
         public ItemContainerInfo Materialize(
             int index,

+ 3 - 0
src/Avalonia.Controls/Generators/ItemContainerGenerator`1.cs

@@ -34,6 +34,9 @@ namespace Avalonia.Controls.Generators
             ContentTemplateProperty = contentTemplateProperty;
         }
 
+        /// <inheritdoc/>
+        public override Type ContainerType => typeof(T);
+
         /// <summary>
         /// Gets the container's Content property.
         /// </summary>

+ 39 - 11
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
         /// <param name="e">The details of the containers.</param>
         protected virtual void OnContainersMaterialized(ItemContainerEventArgs e)
         {
-            var toAdd = new List<ILogical>();
-
             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);
         }
 
         /// <summary>
@@ -248,19 +263,32 @@ namespace Avalonia.Controls
         /// <param name="e">The details of the containers.</param>
         protected virtual void OnContainersDematerialized(ItemContainerEventArgs e)
         {
-            var toRemove = new List<ILogical>();
-
             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);
         }
 
         /// <summary>

+ 3 - 2
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<ContentPresenter>(child);
-            Assert.Equal("Foo", ((ContentPresenter)child).Content);
+            
+            Assert.IsType<TextBlock>(child);
+            Assert.Equal("Foo", ((TextBlock)child).Text);
         }
 
         [Fact]

+ 31 - 2
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<ContentPresenter>(logical.LogicalChildren[0]);
+            Assert.IsType<TextBlock>(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()
         {