Преглед изворни кода

Make ItemContainerGenerator create containers

Make the untyped ItemContainerGenerator create `ContentPresenter`
containers when the data isn't a control. This is required for correct
binding to `DataContext` in a data template.
Steven Kirk пре 9 година
родитељ
комит
fbb7ea759b

+ 8 - 6
src/Avalonia.Controls/Generators/ItemContainerGenerator.cs

@@ -2,12 +2,10 @@
 // Licensed under the MIT license. See licence.md file in the project root for full license information.
 
 using System;
-using System.Collections;
 using System.Collections.Generic;
 using System.Linq;
-using System.Reactive.Subjects;
+using Avalonia.Controls.Presenters;
 using Avalonia.Controls.Templates;
-using Avalonia.Controls.Utils;
 
 namespace Avalonia.Controls.Generators
 {
@@ -185,11 +183,15 @@ namespace Avalonia.Controls.Generators
         /// <returns>The created container control.</returns>
         protected virtual IControl CreateContainer(object item)
         {
-            var result = Owner.MaterializeDataTemplate(item, ItemTemplate);
+            var result = item as IControl;
 
-            if (result != null && !(item is IControl))
+            if (result == null)
             {
-                result.DataContext = item;
+                result = new ContentPresenter
+                {
+                    ContentTemplate = ItemTemplate,
+                    Content = item,
+                };
             }
 
             return result;

+ 0 - 1
tests/Avalonia.Controls.UnitTests/Avalonia.Controls.UnitTests.csproj

@@ -102,7 +102,6 @@
     <Compile Include="HeaderedItemsControlTests .cs" />
     <Compile Include="ControlTests_NameScope.cs" />
     <Compile Include="Generators\ItemContainerGeneratorTests.cs" />
-    <Compile Include="Generators\ItemContainerGeneratorTypedTests.cs" />
     <Compile Include="GridLengthTests.cs" />
     <Compile Include="ImageTests.cs" />
     <Compile Include="Presenters\ContentPresenterTests.cs" />

+ 2 - 2
tests/Avalonia.Controls.UnitTests/CarouselTests.cs

@@ -50,8 +50,8 @@ namespace Avalonia.Controls.UnitTests
             Assert.Equal(1, target.GetLogicalChildren().Count());
 
             var child = target.GetLogicalChildren().Single();
-            Assert.IsType<TextBlock>(child);
-            Assert.Equal("Foo", ((TextBlock)child).Text);
+            Assert.IsType<ContentPresenter>(child);
+            Assert.Equal("Foo", ((ContentPresenter)child).Content);
         }
 
         [Fact]

+ 3 - 2
tests/Avalonia.Controls.UnitTests/Generators/ItemContainerGeneratorTests.cs

@@ -4,6 +4,7 @@
 using System.Collections.Generic;
 using System.Linq;
 using Avalonia.Controls.Generators;
+using Avalonia.Controls.Presenters;
 using Xunit;
 
 namespace Avalonia.Controls.UnitTests.Generators
@@ -19,8 +20,8 @@ namespace Avalonia.Controls.UnitTests.Generators
             var containers = Materialize(target, 0, items);
             var result = containers
                 .Select(x => x.ContainerControl)
-                .OfType<TextBlock>()
-                .Select(x => x.Text)
+                .OfType<ContentPresenter>()
+                .Select(x => x.Content)
                 .ToList();
 
             Assert.Equal(items, result);

+ 16 - 11
tests/Avalonia.Controls.UnitTests/ItemsControlTests.cs

@@ -27,7 +27,10 @@ namespace Avalonia.Controls.UnitTests
             target.ApplyTemplate();
             target.Presenter.ApplyTemplate();
 
-            Assert.IsType<Canvas>(target.Presenter.Panel.Children[0]);
+            var container = (ContentPresenter)target.Presenter.Panel.Children[0];
+            container.UpdateChild();
+
+            Assert.IsType<Canvas>(container.Child);
         }
 
         [Fact]
@@ -44,7 +47,7 @@ namespace Avalonia.Controls.UnitTests
         }
 
         [Fact]
-        public void Item_Should_Have_TemplatedParent_Set_To_Null()
+        public void Container_Should_Have_TemplatedParent_Set_To_Null()
         {
             var target = new ItemsControl();
 
@@ -53,9 +56,9 @@ namespace Avalonia.Controls.UnitTests
             target.ApplyTemplate();
             target.Presenter.ApplyTemplate();
 
-            var item = (TextBlock)target.Presenter.Panel.GetVisualChildren().First();
+            var container = (ContentPresenter)target.Presenter.Panel.Children[0];
 
-            Assert.Null(item.TemplatedParent);
+            Assert.Null(container.TemplatedParent);
         }
 
         [Fact]
@@ -135,7 +138,7 @@ namespace Avalonia.Controls.UnitTests
         }
 
         [Fact]
-        public void Adding_String_Item_Should_Make_TextBlock_Appear_In_LogicalChildren()
+        public void Adding_String_Item_Should_Make_ContentPresenter_Appear_In_LogicalChildren()
         {
             var target = new ItemsControl();
             var child = new Control();
@@ -147,7 +150,7 @@ namespace Avalonia.Controls.UnitTests
 
             var logical = (ILogical)target;
             Assert.Equal(1, logical.LogicalChildren.Count);
-            Assert.IsType<TextBlock>(logical.LogicalChildren[0]);
+            Assert.IsType<ContentPresenter>(logical.LogicalChildren[0]);
         }
 
         [Fact]
@@ -390,8 +393,8 @@ namespace Avalonia.Controls.UnitTests
             target.Presenter.ApplyTemplate();
 
             var text = target.Presenter.Panel.Children
-                .Cast<TextBlock>()
-                .Select(x => x.Text)
+                .Cast<ContentPresenter>()
+                .Select(x => x.Content)
                 .ToList();
 
             Assert.Equal(new[] { "Foo", "Bar" }, text);
@@ -419,7 +422,7 @@ namespace Avalonia.Controls.UnitTests
         }
 
         [Fact]
-        public void DataTemplate_Created_Item_Should_Be_NameScope()
+        public void DataTemplate_Created_Content_Should_Be_NameScope()
         {
             var items = new object[]
             {
@@ -435,8 +438,10 @@ namespace Avalonia.Controls.UnitTests
             target.ApplyTemplate();
             target.Presenter.ApplyTemplate();
 
-            var item = target.Presenter.Panel.LogicalChildren[0];
-            Assert.NotNull(NameScope.GetNameScope((TextBlock)item));
+            var container = (ContentPresenter)target.Presenter.Panel.LogicalChildren[0];
+            container.UpdateChild();
+
+            Assert.NotNull(NameScope.GetNameScope((TextBlock)container.Child));
         }
 
         private class Item

+ 4 - 4
tests/Avalonia.Controls.UnitTests/Presenters/CarouselPresenterTests.cs

@@ -60,8 +60,8 @@ namespace Avalonia.Controls.UnitTests.Presenters
 
             target.ApplyTemplate();
 
-            Assert.IsType<TextBlock>(target.Panel.Children[0]);
-            Assert.Equal("foo", ((TextBlock)target.Panel.Children[0]).Text);
+            Assert.IsType<ContentPresenter>(target.Panel.Children[0]);
+            Assert.Equal("foo", ((ContentPresenter)target.Panel.Children[0]).Content);
         }
 
         [Fact]
@@ -76,8 +76,8 @@ namespace Avalonia.Controls.UnitTests.Presenters
             target.ApplyTemplate();
             target.SelectedIndex = 1;
 
-            Assert.IsType<TextBlock>(target.Panel.Children[0]);
-            Assert.Equal("bar", ((TextBlock)target.Panel.Children[0]).Text);
+            Assert.IsType<ContentPresenter>(target.Panel.Children[0]);
+            Assert.Equal("bar", ((ContentPresenter)target.Panel.Children[0]).Content);
         }
 
         [Fact]

+ 24 - 21
tests/Avalonia.Controls.UnitTests/Presenters/ItemsPresenterTests.cs

@@ -38,10 +38,10 @@ namespace Avalonia.Controls.UnitTests.Presenters
             target.ApplyTemplate();
 
             Assert.Equal(2, target.Panel.Children.Count);
-            Assert.IsType<TextBlock>(target.Panel.Children[0]);
-            Assert.IsType<TextBlock>(target.Panel.Children[1]);
-            Assert.Equal("foo", ((TextBlock)target.Panel.Children[0]).Text);
-            Assert.Equal("bar", ((TextBlock)target.Panel.Children[1]).Text);
+            Assert.IsType<ContentPresenter>(target.Panel.Children[0]);
+            Assert.IsType<ContentPresenter>(target.Panel.Children[1]);
+            Assert.Equal("foo", ((ContentPresenter)target.Panel.Children[0]).Content);
+            Assert.Equal("bar", ((ContentPresenter)target.Panel.Children[1]).Content);
         }
 
         [Fact]
@@ -88,8 +88,8 @@ namespace Avalonia.Controls.UnitTests.Presenters
             items.RemoveAt(0);
 
             Assert.Equal(1, target.Panel.Children.Count);
-            Assert.Equal("bar", ((TextBlock)target.Panel.Children[0]).Text);
-            Assert.Equal("bar", ((TextBlock)target.ItemContainerGenerator.ContainerFromIndex(0)).Text);
+            Assert.Equal("bar", ((ContentPresenter)target.Panel.Children[0]).Content);
+            Assert.Equal("bar", ((ContentPresenter)target.ItemContainerGenerator.ContainerFromIndex(0)).Content);
         }
 
         [Fact]
@@ -121,8 +121,8 @@ namespace Avalonia.Controls.UnitTests.Presenters
             items[1] = "baz";
 
             var text = target.Panel.Children
-                .OfType<TextBlock>()
-                .Select(x => x.Text)
+                .OfType<ContentPresenter>()
+                .Select(x => x.Content)
                 .ToList();
 
             Assert.Equal(new[] { "foo", "baz", "baz" }, text);
@@ -141,8 +141,8 @@ namespace Avalonia.Controls.UnitTests.Presenters
             items.Move(2, 1);
 
             var text = target.Panel.Children
-                .OfType<TextBlock>()
-                .Select(x => x.Text)
+                .OfType<ContentPresenter>()
+                .Select(x => x.Content)
                 .ToList();
 
             Assert.Equal(new[] { "foo", "baz", "bar" }, text);
@@ -161,8 +161,8 @@ namespace Avalonia.Controls.UnitTests.Presenters
             items.Insert(2, "insert");
 
             var text = target.Panel.Children
-                .OfType<TextBlock>()
-                .Select(x => x.Text)
+                .OfType<ContentPresenter>()
+                .Select(x => x.Content)
                 .ToList();
 
             Assert.Equal(new[] { "foo", "bar", "insert", "baz" }, text);
@@ -195,16 +195,16 @@ namespace Avalonia.Controls.UnitTests.Presenters
 
             target.ApplyTemplate();
 
-            var text = target.Panel.Children.Cast<TextBlock>().Select(x => x.Text).ToList();
+            var text = target.Panel.Children.Cast<ContentPresenter>().Select(x => x.Content).ToList();
 
-            Assert.Equal(new[] { "foo", "bar" }, text);
+            Assert.Equal(new[] { "foo", null, "bar" }, text);
             Assert.NotNull(target.ItemContainerGenerator.ContainerFromIndex(0));
-            Assert.Null(target.ItemContainerGenerator.ContainerFromIndex(1));
+            Assert.NotNull(target.ItemContainerGenerator.ContainerFromIndex(1));
             Assert.NotNull(target.ItemContainerGenerator.ContainerFromIndex(2));
 
             items.RemoveAt(1);
 
-            text = target.Panel.Children.Cast<TextBlock>().Select(x => x.Text).ToList();
+            text = target.Panel.Children.Cast<ContentPresenter>().Select(x => x.Content).ToList();
 
             Assert.Equal(new[] { "foo", "bar" }, text);
             Assert.NotNull(target.ItemContainerGenerator.ContainerFromIndex(0));
@@ -224,8 +224,11 @@ namespace Avalonia.Controls.UnitTests.Presenters
             target.ApplyTemplate();
             items.RemoveAt(2);
 
-            var text = target.Panel.Children.OfType<TextBlock>().Select(x => x.Text);
-            Assert.Equal(new[] { "1", "2" }, text);
+            var numbers = target.Panel.Children
+                .OfType<ContentPresenter>()
+                .Select(x => x.Content)
+                .Cast<int>();
+            Assert.Equal(new[] { 1, 2 }, numbers);
         }
 
         [Fact]
@@ -288,8 +291,8 @@ namespace Avalonia.Controls.UnitTests.Presenters
             target.ApplyTemplate();
 
             var text = target.Panel.Children
-                .Cast<TextBlock>()
-                .Select(x => x.Text)
+                .Cast<ContentPresenter>()
+                .Select(x => x.Content)
                 .ToList();
 
             Assert.Equal(new[] { "Foo", "Bar" }, text);
@@ -308,7 +311,7 @@ namespace Avalonia.Controls.UnitTests.Presenters
             target.ApplyTemplate();
 
             var dataContexts = target.Panel.Children
-                .Cast<TextBlock>()
+                .Cast<ContentPresenter>()
                 .Select(x => x.DataContext)
                 .ToList();
 

+ 11 - 5
tests/Avalonia.Controls.UnitTests/TabControlTests.cs

@@ -184,23 +184,29 @@ namespace Avalonia.Controls.UnitTests
             ApplyTemplate(target);
             var carousel = (Carousel)target.Pages;
 
-            var dataContext = ((TextBlock)carousel.Presenter.Panel.GetLogicalChildren().Single()).DataContext;
+            var container = (ContentPresenter)carousel.Presenter.Panel.Children.Single();
+            container.UpdateChild();
+            var dataContext = ((TextBlock)container.Child).DataContext;
             Assert.Equal(items[0], dataContext);
 
             target.SelectedIndex = 1;
-            dataContext = ((Button)carousel.Presenter.Panel.GetLogicalChildren().Single()).DataContext;
+            container = (ContentPresenter)carousel.Presenter.Panel.Children.Single();
+            container.UpdateChild();
+            dataContext = ((Button)container.Child).DataContext;
             Assert.Equal(items[1], dataContext);
 
             target.SelectedIndex = 2;
-            dataContext = ((TextBlock)carousel.Presenter.Panel.GetLogicalChildren().Single()).DataContext;
+            dataContext = ((TextBlock)carousel.Presenter.Panel.Children.Single()).DataContext;
             Assert.Equal("Base", dataContext);
 
             target.SelectedIndex = 3;
-            dataContext = ((TextBlock)carousel.Presenter.Panel.GetLogicalChildren().Single()).DataContext;
+            container = (ContentPresenter)carousel.Presenter.Panel.Children[0];
+            container.UpdateChild();
+            dataContext = ((TextBlock)container.Child).DataContext;
             Assert.Equal("Qux", dataContext);
 
             target.SelectedIndex = 4;
-            dataContext = ((TextBlock)carousel.Presenter.Panel.GetLogicalChildren().Single()).DataContext;
+            dataContext = ((TextBlock)carousel.Presenter.Panel.Children.Single()).DataContext;
             Assert.Equal("Base", dataContext);
         }