diff --git a/Perspex.Controls.UnitTests/Perspex.Controls.UnitTests.csproj b/Perspex.Controls.UnitTests/Perspex.Controls.UnitTests.csproj index 0e234939cb..e14fd7eb8d 100644 --- a/Perspex.Controls.UnitTests/Perspex.Controls.UnitTests.csproj +++ b/Perspex.Controls.UnitTests/Perspex.Controls.UnitTests.csproj @@ -60,6 +60,7 @@ + diff --git a/Perspex.Controls.UnitTests/TemplatedControlTests.cs b/Perspex.Controls.UnitTests/TemplatedControlTests.cs index bb60e46d11..f4fdee5883 100644 --- a/Perspex.Controls.UnitTests/TemplatedControlTests.cs +++ b/Perspex.Controls.UnitTests/TemplatedControlTests.cs @@ -4,6 +4,7 @@ // // ----------------------------------------------------------------------- +using Microsoft.VisualStudio.TestTools.UnitTesting; namespace Perspex.Controls.UnitTests { using System; @@ -96,5 +97,22 @@ namespace Perspex.Controls.UnitTests Assert.AreEqual(target, templateResult.TemplatedParent); } + + [TestMethod] + public void OnTemplateApplied_Is_Called() + { + var target = new TestTemplatedControl + { + Template = new ControlTemplate(_ => + { + return new Control(); + }) + }; + + var children = ((IVisual)target).VisualChildren.ToArray(); + + Assert.IsTrue(target.OnTemplateAppliedCalled); + } } } + diff --git a/Perspex.Controls.UnitTests/TestTemplatedControl.cs b/Perspex.Controls.UnitTests/TestTemplatedControl.cs new file mode 100644 index 0000000000..a019396a69 --- /dev/null +++ b/Perspex.Controls.UnitTests/TestTemplatedControl.cs @@ -0,0 +1,23 @@ +// ----------------------------------------------------------------------- +// +// Copyright 2014 MIT Licence. See licence.md for more information. +// +// ----------------------------------------------------------------------- + +namespace Perspex.Controls.UnitTests +{ + using System; + using Moq; + using Perspex.Layout; + using Perspex.Rendering; + + internal class TestTemplatedControl : TemplatedControl + { + public bool OnTemplateAppliedCalled { get; private set; } + + protected override void OnTemplateApplied() + { + this.OnTemplateAppliedCalled = true; + } + } +} diff --git a/Perspex.Controls/ContentPresenter.cs b/Perspex.Controls/ContentPresenter.cs index 6185df26ef..c852efb0ed 100644 --- a/Perspex.Controls/ContentPresenter.cs +++ b/Perspex.Controls/ContentPresenter.cs @@ -32,7 +32,7 @@ namespace Perspex.Controls set { this.SetValue(ContentProperty, value); } } - protected override IEnumerable CreateVisualChildren() + protected override void CreateVisualChildren() { object content = this.Content; @@ -62,11 +62,7 @@ namespace Perspex.Controls } result.TemplatedParent = null; - return Enumerable.Repeat(result, 1); - } - else - { - return Enumerable.Empty(); + this.AddVisualChild(result); } } @@ -142,9 +138,8 @@ namespace Perspex.Controls private void ContentChanged(Tuple content) { - var children = this.CreateVisualChildren(); this.ClearVisualChildren(); - this.AddVisualChildren(children); + this.CreateVisualChildren(); this.InvalidateMeasure(); } } diff --git a/Perspex.Controls/Control.cs b/Perspex.Controls/Control.cs index 28fca57c67..53164ac817 100644 --- a/Perspex.Controls/Control.cs +++ b/Perspex.Controls/Control.cs @@ -213,7 +213,7 @@ namespace Perspex.Controls // TODO: This needs to traverse the logical tree, not the visual. foreach (var i in this.GetVisualAncestors().OfType()) { - foreach (DataTemplate dt in control.DataTemplates.Reverse()) + foreach (DataTemplate dt in i.DataTemplates.Reverse()) { if (dt.Match(content)) { diff --git a/Perspex.Controls/ItemsPresenter.cs b/Perspex.Controls/ItemsPresenter.cs index a1600dfb98..faa96da34b 100644 --- a/Perspex.Controls/ItemsPresenter.cs +++ b/Perspex.Controls/ItemsPresenter.cs @@ -52,9 +52,10 @@ namespace Perspex.Controls return finalSize; } - protected override IEnumerable CreateVisualChildren() + protected override void CreateVisualChildren() { - return Enumerable.Repeat(this.GetPanel(), 1); + this.AddVisualChild(this.GetPanel()); + this.ItemsChanged(Tuple.Create(default(IEnumerable), this.Items)); } private Control CreateItemControl(object item) @@ -111,7 +112,6 @@ namespace Perspex.Controls if (this.panel == null && this.ItemsPanel != null) { this.panel = this.ItemsPanel.Build(); - this.ItemsChanged(Tuple.Create(default(IEnumerable), this.Items)); } return this.panel; diff --git a/Perspex.Controls/TemplatedControl.cs b/Perspex.Controls/TemplatedControl.cs index 60f987fde9..c7f2732132 100644 --- a/Perspex.Controls/TemplatedControl.cs +++ b/Perspex.Controls/TemplatedControl.cs @@ -13,7 +13,7 @@ namespace Perspex.Controls using Perspex.Styling; using Splat; - public class TemplatedControl : Control, IVisual, ITemplatedControl + public class TemplatedControl : Control, ITemplatedControl { public static readonly PerspexProperty TemplateProperty = PerspexProperty.Register("Template"); @@ -56,7 +56,7 @@ namespace Perspex.Controls return new Size(); } - protected override IEnumerable CreateVisualChildren() + protected override void CreateVisualChildren() { if (this.Template != null) { @@ -66,11 +66,8 @@ namespace Perspex.Controls this.GetHashCode())); var child = this.Template.Build(this); - return Enumerable.Repeat(child, 1); - } - else - { - return Enumerable.Empty(); + this.AddVisualChild(child); + this.OnTemplateApplied(); } } diff --git a/Perspex.Controls/TreeViewItem.cs b/Perspex.Controls/TreeViewItem.cs index fb103e8d62..c8ebbb4f2b 100644 --- a/Perspex.Controls/TreeViewItem.cs +++ b/Perspex.Controls/TreeViewItem.cs @@ -6,6 +6,7 @@ namespace Perspex.Controls { + using System; using System.Linq; public class TreeViewItem : HeaderedItemsControl @@ -44,7 +45,7 @@ namespace Perspex.Controls } else { - return null; + throw new InvalidOperationException("TreeViewItem must be added to TreeView."); } } diff --git a/Perspex.SceneGraph.UnitTests/TestVisual.cs b/Perspex.SceneGraph.UnitTests/TestVisual.cs index a780cf6a18..2b4348ae27 100644 --- a/Perspex.SceneGraph.UnitTests/TestVisual.cs +++ b/Perspex.SceneGraph.UnitTests/TestVisual.cs @@ -50,9 +50,12 @@ namespace Perspex.SceneGraph.UnitTests this.ClearVisualChildren(); } - protected override IEnumerable CreateVisualChildren() + protected override void CreateVisualChildren() { - return this.InitialChildren ?? Enumerable.Empty(); + if (this.InitialChildren != null) + { + this.AddVisualChildren(this.InitialChildren); + } } protected override void OnVisualParentChanged(Visual oldParent) diff --git a/Perspex.SceneGraph/Visual.cs b/Perspex.SceneGraph/Visual.cs index db706eb3d7..533ef69ecc 100644 --- a/Perspex.SceneGraph/Visual.cs +++ b/Perspex.SceneGraph/Visual.cs @@ -109,12 +109,16 @@ namespace Perspex protected void AddVisualChild(Visual visual) { + Contract.Requires(visual != null); + this.EnsureVisualChildrenCreated(); this.visualChildren.Add(visual); } protected void AddVisualChildren(IEnumerable visuals) { + Contract.Requires(visuals != null); + this.EnsureVisualChildrenCreated(); this.visualChildren.AddRange(visuals); } @@ -133,6 +137,8 @@ namespace Perspex protected void RemoveVisualChild(Visual visual) { + Contract.Requires(visual != null); + this.EnsureVisualChildrenCreated(); this.visualChildren.Remove(visual); } @@ -142,9 +148,8 @@ namespace Perspex this.bounds = bounds; } - protected virtual IEnumerable CreateVisualChildren() + protected virtual void CreateVisualChildren() { - return Enumerable.Empty(); } protected virtual void OnAttachedToVisualTree(IRenderRoot root) @@ -175,7 +180,7 @@ namespace Perspex { this.visualChildren = new PerspexList(); this.visualChildren.CollectionChanged += VisualChildrenChanged; - this.visualChildren.AddRange(this.CreateVisualChildren()); + this.CreateVisualChildren(); } } diff --git a/Perspex.Windows/Window.cs b/Perspex.Windows/Window.cs index 27e5710f9e..f2b8fcfcd5 100644 --- a/Perspex.Windows/Window.cs +++ b/Perspex.Windows/Window.cs @@ -56,6 +56,7 @@ namespace Perspex.Windows { this.LayoutManager.ExecuteLayoutPass(); this.renderer.Render(this); + this.RenderManager.RenderFinished(); this.layoutPending = false; }); }); @@ -67,8 +68,11 @@ namespace Perspex.Windows DispatcherPriority.Render, () => { - this.renderer.Render(this); - this.RenderManager.RenderFinished(); + if (!this.layoutPending) + { + this.renderer.Render(this); + this.RenderManager.RenderFinished(); + } }); }); }