Browse Source

Added failing test for #1271.

Steven Kirk 8 years ago
parent
commit
2e8521e690
1 changed files with 58 additions and 0 deletions
  1. 58 0
      tests/Avalonia.Controls.UnitTests/ContentControlTests.cs

+ 58 - 0
tests/Avalonia.Controls.UnitTests/ContentControlTests.cs

@@ -1,6 +1,7 @@
 // Copyright (c) The Avalonia Project. All rights reserved.
 // Licensed under the MIT license. See licence.md file in the project root for full license information.
 
+using System;
 using System.Collections.Specialized;
 using System.Linq;
 using Moq;
@@ -11,6 +12,9 @@ using Avalonia.Styling;
 using Avalonia.UnitTests;
 using Avalonia.VisualTree;
 using Xunit;
+using Avalonia.Markup.Xaml.Data;
+using Avalonia.Data;
+using System.Collections.Generic;
 
 namespace Avalonia.Controls.UnitTests
 {
@@ -273,6 +277,60 @@ namespace Avalonia.Controls.UnitTests
             Assert.Null(target.Presenter.Child.DataContext);
         }
 
+        [Fact]
+        public void Binding_ContentTemplate_After_Content_Does_Not_Leave_Orpaned_TextBlock()
+        {
+            // Test for #1271.
+            var children = new List<IControl>();
+            var presenter = new ContentPresenter();
+
+            // The content and then the content template property need to be bound with delayed bindings
+            // as they are in Avalonia.Markup.Xaml.
+            DelayedBinding.Add(presenter, ContentPresenter.ContentProperty, new Binding("Content")
+            {
+                Priority = BindingPriority.TemplatedParent,
+                RelativeSource = new RelativeSource(RelativeSourceMode.TemplatedParent),
+            });
+
+            DelayedBinding.Add(presenter, ContentPresenter.ContentTemplateProperty, new Binding("ContentTemplate")
+            {
+                Priority = BindingPriority.TemplatedParent,
+                RelativeSource = new RelativeSource(RelativeSourceMode.TemplatedParent),
+            });
+
+            presenter.GetObservable(ContentPresenter.ChildProperty).Subscribe(children.Add);
+
+            var target = new ContentControl
+            {
+                Template = new FuncControlTemplate<ContentControl>(_ => presenter),
+                ContentTemplate = new FuncDataTemplate<string>(x => new Canvas()),
+                Content = "foo",
+            };
+                        
+            // The control must be rooted.
+            var root = new TestRoot
+            {
+                Child = target,
+            };
+
+            target.ApplyTemplate();
+
+            // When the template is applied, the Content property is bound before the ContentTemplate
+            // property, causing a TextBlock to be created by the default template before ContentTemplate
+            // is bound.
+            Assert.Collection(
+                children,
+                x => Assert.Null(x),
+                x => Assert.IsType<TextBlock>(x),
+                x => Assert.IsType<Canvas>(x));
+
+            var textBlock = (TextBlock)children[1];
+
+            // The leak in #1271 was caused by the TextBlock's logical parent not being cleared when
+            // it is replaced by the Canvas.
+            Assert.Null(textBlock.GetLogicalParent());
+        }
+
         private FuncControlTemplate GetTemplate()
         {
             return new FuncControlTemplate<ContentControl>(parent =>