diff --git a/Perspex.Controls.UnitTests/DropDownTests.cs b/Perspex.Controls.UnitTests/DropDownTests.cs
new file mode 100644
index 0000000000..40a582821a
--- /dev/null
+++ b/Perspex.Controls.UnitTests/DropDownTests.cs
@@ -0,0 +1,254 @@
+// -----------------------------------------------------------------------
+//
+// Copyright 2014 MIT Licence. See licence.md for more information.
+//
+// -----------------------------------------------------------------------
+
+namespace Perspex.Controls.UnitTests
+{
+ using System;
+ using System.Collections.Specialized;
+ using System.Linq;
+ using Microsoft.VisualStudio.TestTools.UnitTesting;
+ using Moq;
+ using Perspex.Controls;
+ using Perspex.Controls.Presenters;
+ using Perspex.Platform;
+ using Perspex.Styling;
+ using Perspex.VisualTree;
+ using Ploeh.AutoFixture;
+ using Ploeh.AutoFixture.AutoMoq;
+ using Splat;
+
+ [TestClass]
+ public class DropDownTests
+ {
+ [TestMethod]
+ public void Template_Should_Be_Instantiated()
+ {
+ using (var ctx = this.RegisterServices())
+ {
+ var target = new DropDown();
+ target.Content = "Foo";
+ target.Template = this.GetTemplate();
+
+ target.Measure(new Size(100, 100));
+
+ var child = ((IVisual)target).VisualChildren.Single();
+ Assert.IsInstanceOfType(child, typeof(Border));
+ child = child.VisualChildren.Single();
+ Assert.IsInstanceOfType(child, typeof(ContentPresenter));
+ child = child.VisualChildren.Single();
+ Assert.IsInstanceOfType(child, typeof(TextBlock));
+ }
+ }
+
+ [TestMethod]
+ public void Templated_Children_Should_Be_Styled()
+ {
+ using (var ctx = this.RegisterServices())
+ {
+ var root = new TestRoot();
+ var target = new DropDown();
+ var styler = new Mock();
+
+ Locator.CurrentMutable.Register(() => styler.Object, typeof(IStyler));
+ target.Content = "Foo";
+ target.Template = this.GetTemplate();
+ root.Content = target;
+
+ target.ApplyTemplate();
+
+ styler.Verify(x => x.ApplyStyles(It.IsAny()), Times.Once());
+ styler.Verify(x => x.ApplyStyles(It.IsAny()), Times.Once());
+ styler.Verify(x => x.ApplyStyles(It.IsAny()), Times.Once());
+ styler.Verify(x => x.ApplyStyles(It.IsAny()), Times.Once());
+ }
+ }
+
+ [TestMethod]
+ public void ContentPresenter_Should_Have_TemplatedParent_Set()
+ {
+ var target = new DropDown();
+ var child = new Border();
+
+ target.Template = this.GetTemplate();
+ target.Content = child;
+ target.ApplyTemplate();
+
+ var contentPresenter = child.GetVisualParent();
+ Assert.AreEqual(target, contentPresenter.TemplatedParent);
+ }
+
+ [TestMethod]
+ public void Content_Should_Have_TemplatedParent_Set_To_Null()
+ {
+ var target = new DropDown();
+ var child = new Border();
+
+ target.Template = this.GetTemplate();
+ target.Content = child;
+ target.ApplyTemplate();
+
+ Assert.IsNull(child.TemplatedParent);
+ }
+
+ [TestMethod]
+ public void Setting_Content_Should_Set_Child_Controls_Parent()
+ {
+ var target = new DropDown();
+ var child = new Control();
+
+ target.Content = child;
+
+ Assert.AreEqual(child.Parent, target);
+ Assert.AreEqual(((ILogical)child).LogicalParent, target);
+ }
+
+ [TestMethod]
+ public void Clearing_Content_Should_Clear_Child_Controls_Parent()
+ {
+ var target = new DropDown();
+ var child = new Control();
+
+ target.Content = child;
+ target.Content = null;
+
+ Assert.IsNull(child.Parent);
+ Assert.IsNull(((ILogical)child).LogicalParent);
+ }
+
+ [TestMethod]
+ public void Setting_Content_To_Control_Should_Make_Control_Appear_In_LogicalChildren()
+ {
+ var target = new DropDown();
+ var child = new Control();
+
+ target.Template = this.GetTemplate();
+ target.Content = child;
+ target.ApplyTemplate();
+
+ CollectionAssert.AreEqual(new[] { child }, ((ILogical)target).LogicalChildren.ToList());
+ }
+
+ [TestMethod]
+ public void Setting_Content_To_String_Should_Make_TextBlock_Appear_In_LogicalChildren()
+ {
+ var target = new DropDown();
+ var child = new Control();
+
+ target.Template = this.GetTemplate();
+ target.Content = "Foo";
+ target.ApplyTemplate();
+
+ var logical = (ILogical)target;
+ Assert.AreEqual(1, logical.LogicalChildren.Count);
+ Assert.IsInstanceOfType(logical.LogicalChildren[0], typeof(TextBlock));
+ }
+
+ [TestMethod]
+ public void Clearing_Content_Should_Remove_From_LogicalChildren()
+ {
+ var target = new DropDown();
+ var child = new Control();
+
+ target.Content = child;
+ target.Content = null;
+
+ CollectionAssert.AreEqual(new ILogical[0], ((ILogical)target).LogicalChildren.ToList());
+ }
+
+ [TestMethod]
+ public void Setting_Content_Should_Fire_LogicalChildren_CollectionChanged()
+ {
+ var target = new DropDown();
+ var child = new Control();
+ var called = false;
+
+ ((ILogical)target).LogicalChildren.CollectionChanged += (s, e) =>
+ called = e.Action == NotifyCollectionChangedAction.Add;
+
+ target.Template = this.GetTemplate();
+ target.Content = child;
+ target.ApplyTemplate();
+
+ // Need to call ApplyTemplate on presenter for CollectionChanged to be called.
+ var presenter = target.GetTemplateControls().Single(x => x.Id == "contentPresenter");
+ presenter.ApplyTemplate();
+
+ Assert.IsTrue(called);
+ }
+
+ [TestMethod]
+ public void Clearing_Content_Should_Fire_LogicalChildren_CollectionChanged()
+ {
+ var target = new DropDown();
+ var child = new Control();
+ var called = false;
+
+ target.Template = this.GetTemplate();
+ target.Content = child;
+ target.ApplyTemplate();
+
+ ((ILogical)target).LogicalChildren.CollectionChanged += (s, e) =>
+ called = e.Action == NotifyCollectionChangedAction.Remove;
+
+ target.Content = null;
+
+ // Need to call ApplyTemplate on presenter for CollectionChanged to be called.
+ var presenter = target.GetTemplateControls().Single(x => x.Id == "contentPresenter");
+ presenter.ApplyTemplate();
+
+ Assert.IsTrue(called);
+ }
+
+ [TestMethod]
+ public void Changing_Content_Should_Fire_LogicalChildren_CollectionChanged()
+ {
+ var target = new DropDown();
+ var child1 = new Control();
+ var child2 = new Control();
+ var called = false;
+
+ target.Template = this.GetTemplate();
+ target.Content = child1;
+ target.ApplyTemplate();
+
+ ((ILogical)target).LogicalChildren.CollectionChanged += (s, e) =>
+ called = e.Action == NotifyCollectionChangedAction.Replace;
+
+ target.Content = child2;
+
+ // Need to call ApplyTemplate on presenter for CollectionChanged to be called.
+ var presenter = target.GetTemplateControls().Single(x => x.Id == "contentPresenter");
+ presenter.ApplyTemplate();
+
+ Assert.IsTrue(called);
+ }
+
+ private ControlTemplate GetTemplate()
+ {
+ return ControlTemplate.Create(parent =>
+ {
+ return new Border
+ {
+ Background = new Perspex.Media.SolidColorBrush(0xffffffff),
+ Content = new ContentPresenter
+ {
+ Id = "contentPresenter",
+ [~ContentPresenter.ContentProperty] = parent[~DropDown.ContentProperty],
+ }
+ };
+ });
+ }
+
+ private IDisposable RegisterServices()
+ {
+ var result = Locator.CurrentMutable.WithResolver();
+ var fixture = new Fixture().Customize(new AutoMoqCustomization());
+ var renderInterface = fixture.Create();
+ Locator.CurrentMutable.RegisterConstant(renderInterface, typeof(IPlatformRenderInterface));
+ return result;
+ }
+ }
+}
diff --git a/Perspex.Controls.UnitTests/Perspex.Controls.UnitTests.csproj b/Perspex.Controls.UnitTests/Perspex.Controls.UnitTests.csproj
index 35214ff6b9..f06e046e4e 100644
--- a/Perspex.Controls.UnitTests/Perspex.Controls.UnitTests.csproj
+++ b/Perspex.Controls.UnitTests/Perspex.Controls.UnitTests.csproj
@@ -64,6 +64,7 @@
+
diff --git a/Perspex.Controls/ContentControl.cs b/Perspex.Controls/ContentControl.cs
index 7b515b4a7e..94670d9b64 100644
--- a/Perspex.Controls/ContentControl.cs
+++ b/Perspex.Controls/ContentControl.cs
@@ -31,21 +31,7 @@ namespace Perspex.Controls
public ContentControl()
{
- this.GetObservableWithHistory(ContentProperty).Subscribe(x =>
- {
- var control1 = x.Item1 as Control;
- var control2 = x.Item2 as Control;
-
- if (control1 != null)
- {
- control1.Parent = null;
- }
-
- if (control2 != null)
- {
- control2.Parent = this;
- }
- });
+ this.GetObservableWithHistory(ContentProperty).Subscribe(this.SetContentParent);
}
public object Content
@@ -54,11 +40,6 @@ namespace Perspex.Controls
set { this.SetValue(ContentProperty, value); }
}
- IReadOnlyPerspexList ILogical.LogicalChildren
- {
- get { return this.logicalChild; }
- }
-
public HorizontalAlignment HorizontalContentAlignment
{
get { return this.GetValue(HorizontalContentAlignmentProperty); }
@@ -71,6 +52,11 @@ namespace Perspex.Controls
set { this.SetValue(VerticalContentAlignmentProperty, value); }
}
+ IReadOnlyPerspexList ILogical.LogicalChildren
+ {
+ get { return this.logicalChild; }
+ }
+
protected override void OnTemplateApplied()
{
if (this.presenterSubscription != null)
@@ -87,5 +73,21 @@ namespace Perspex.Controls
.Subscribe(x => this.logicalChild.SingleItem = x);
}
}
+
+ private void SetContentParent(Tuple