From fc5ff22d8eff8e6b2650d43a91fddaeb9e787361 Mon Sep 17 00:00:00 2001 From: Steven Kirk Date: Fri, 23 Jan 2015 20:21:40 +0100 Subject: [PATCH] Search logical tree for DataTemplates. --- Perspex.Controls.UnitTests/PanelTests.cs | 29 ++++++++++++ Perspex.Controls/DataTemplateExtensions.cs | 5 +-- .../Generators/ItemContainerGenerator.cs | 1 + Perspex.Controls/Panel.cs | 45 ++++++++++++------- Perspex.Controls/Popup.cs | 2 +- Perspex.Controls/Presenters/ItemsPresenter.cs | 1 + .../Primitives/TemplatedControl.cs | 1 + 7 files changed, 63 insertions(+), 21 deletions(-) diff --git a/Perspex.Controls.UnitTests/PanelTests.cs b/Perspex.Controls.UnitTests/PanelTests.cs index f4976e9399..8734ef1146 100644 --- a/Perspex.Controls.UnitTests/PanelTests.cs +++ b/Perspex.Controls.UnitTests/PanelTests.cs @@ -24,6 +24,18 @@ namespace Perspex.Controls.UnitTests Assert.AreEqual(((ILogical)child).LogicalParent, panel); } + [TestMethod] + public void Setting_Controls_Should_Set_Child_Controls_Parent() + { + var panel = new Panel(); + var child = new Control(); + + panel.Children = new Controls { child }; + + Assert.AreEqual(child.Parent, panel); + Assert.AreEqual(((ILogical)child).LogicalParent, panel); + } + [TestMethod] public void Removing_Control_From_Panel_Should_Clear_Child_Controls_Parent() { @@ -54,6 +66,23 @@ namespace Perspex.Controls.UnitTests Assert.IsNull(((ILogical)child2).LogicalParent); } + [TestMethod] + public void Resetting_Panel_Children_Should_Clear_Child_Controls_Parent() + { + var panel = new Panel(); + var child1 = new Control(); + var child2 = new Control(); + + panel.Children.Add(child1); + panel.Children.Add(child2); + panel.Children = new Controls(); + + Assert.IsNull(child1.Parent); + Assert.IsNull(((ILogical)child1).LogicalParent); + Assert.IsNull(child2.Parent); + Assert.IsNull(((ILogical)child2).LogicalParent); + } + [TestMethod] public void Child_Control_Should_Appear_In_Panel_Children() { diff --git a/Perspex.Controls/DataTemplateExtensions.cs b/Perspex.Controls/DataTemplateExtensions.cs index fb937e7461..d4da5c4fb0 100644 --- a/Perspex.Controls/DataTemplateExtensions.cs +++ b/Perspex.Controls/DataTemplateExtensions.cs @@ -7,7 +7,7 @@ namespace Perspex.Controls { using System.Linq; - using Perspex.VisualTree; + using Perspex.LogicalTree; using Splat; public static class DataTemplateExtensions @@ -32,8 +32,7 @@ namespace Perspex.Controls public static IDataTemplate FindDataTemplate(this Control control, object data) { - // TODO: This needs to traverse the logical tree, not the visual. - foreach (var i in control.GetSelfAndVisualAncestors().OfType()) + foreach (var i in control.GetSelfAndLogicalAncestors().OfType()) { foreach (IDataTemplate dt in i.DataTemplates.Reverse()) { diff --git a/Perspex.Controls/Generators/ItemContainerGenerator.cs b/Perspex.Controls/Generators/ItemContainerGenerator.cs index 45551874a2..ad11d02d18 100644 --- a/Perspex.Controls/Generators/ItemContainerGenerator.cs +++ b/Perspex.Controls/Generators/ItemContainerGenerator.cs @@ -83,6 +83,7 @@ namespace Perspex.Controls.Generators foreach (object item in items) { Control container = this.CreateContainerOverride(item); + container.Parent = this.Owner; container.TemplatedParent = null; this.AddInternal(item, container); result.Add(container); diff --git a/Perspex.Controls/Panel.cs b/Perspex.Controls/Panel.cs index 4a1db10ac6..ae9bbf21e3 100644 --- a/Perspex.Controls/Panel.cs +++ b/Perspex.Controls/Panel.cs @@ -7,6 +7,7 @@ namespace Perspex.Controls { using System; + using System.Collections.Generic; using System.Collections.Specialized; using System.Linq; using Perspex.Collections; @@ -39,6 +40,7 @@ namespace Perspex.Controls { if (this.children != null) { + this.ClearLogicalParent(this.children); this.children.CollectionChanged -= this.ChildrenChanged; } @@ -49,50 +51,59 @@ namespace Perspex.Controls { this.children.CollectionChanged += this.ChildrenChanged; this.AddVisualChildren(value); + this.SetLogicalParent(value); this.InvalidateMeasure(); } } } } + public bool IsLogicalParent { get; set; } = true; + IReadOnlyPerspexList ILogical.LogicalChildren { get { return this.children; } } - private void ChildrenChanged(object sender, NotifyCollectionChangedEventArgs e) + private void ClearLogicalParent(IEnumerable controls) { - var logicalParent = (Control)this; + if (this.IsLogicalParent) + { + foreach (var control in controls) + { + control.Parent = null; + } + } + } - while (logicalParent.TemplatedParent != null) + private void SetLogicalParent(IEnumerable controls) + { + if (this.IsLogicalParent) { - logicalParent = (Control)logicalParent.TemplatedParent; + foreach (var control in controls) + { + control.Parent = this; + } } + } - // TODO: Handle Move and Replace. + private void ChildrenChanged(object sender, NotifyCollectionChangedEventArgs e) + { + // TODO: Handle Replace. switch (e.Action) { case NotifyCollectionChangedAction.Add: this.AddVisualChildren(e.NewItems.OfType()); - - foreach (var child in e.NewItems.OfType()) - { - child.Parent = logicalParent; - } - + this.SetLogicalParent(e.NewItems.OfType()); break; case NotifyCollectionChangedAction.Remove: + this.ClearLogicalParent(e.OldItems.OfType()); this.RemoveVisualChildren(e.OldItems.OfType()); - - foreach (var child in e.OldItems.OfType()) - { - child.Parent = null; - } - break; case NotifyCollectionChangedAction.Reset: + this.ClearLogicalParent(e.OldItems.OfType()); this.ClearVisualChildren(); this.AddVisualChildren(this.children); break; diff --git a/Perspex.Controls/Popup.cs b/Perspex.Controls/Popup.cs index 1a8fba46b5..8e19f8f9f6 100644 --- a/Perspex.Controls/Popup.cs +++ b/Perspex.Controls/Popup.cs @@ -44,7 +44,6 @@ namespace Perspex.Controls } }); } - public Control Child { get { return this.GetValue(ChildProperty); } @@ -68,6 +67,7 @@ namespace Perspex.Controls if (this.root == null) { this.root = new PopupRoot(); + this.root.Parent = this; this.root[~PopupRoot.ContentProperty] = this[~ChildProperty]; } diff --git a/Perspex.Controls/Presenters/ItemsPresenter.cs b/Perspex.Controls/Presenters/ItemsPresenter.cs index b2de51a674..0cdc4b709c 100644 --- a/Perspex.Controls/Presenters/ItemsPresenter.cs +++ b/Perspex.Controls/Presenters/ItemsPresenter.cs @@ -65,6 +65,7 @@ namespace Perspex.Controls.Presenters { this.ClearVisualChildren(); this.panel = this.ItemsPanel.Build(); + this.panel.IsLogicalParent = false; this.AddVisualChild(this.panel); this.createdPanel = true; this.ItemsChanged(Tuple.Create(default(IEnumerable), this.Items)); diff --git a/Perspex.Controls/Primitives/TemplatedControl.cs b/Perspex.Controls/Primitives/TemplatedControl.cs index 42aa8667de..516faac6b0 100644 --- a/Perspex.Controls/Primitives/TemplatedControl.cs +++ b/Perspex.Controls/Primitives/TemplatedControl.cs @@ -118,6 +118,7 @@ namespace Perspex.Controls.Primitives var child = this.Template.Build(this); this.AddVisualChild(child); + child.Parent = this; var templateChildren = this.GetVisualDescendents() .OfType()