From 5a1aca287654ffac4d0aeec4f4ecd973ea024b1b Mon Sep 17 00:00:00 2001 From: Steven Kirk Date: Mon, 2 Feb 2015 22:23:12 +0100 Subject: [PATCH] Make template find methods to extension class. --- Perspex.Controls/ContentControl.cs | 1 + Perspex.Controls/ControlExtensions.cs | 16 ------ Perspex.Controls/DropDown.cs | 1 + Perspex.Controls/ItemsControl.cs | 13 +++-- Perspex.Controls/Perspex.Controls.csproj | 1 + .../Primitives/TemplatedControl.cs | 54 +----------------- .../Templates/TemplateExtensions.cs | 57 +++++++++++++++++++ .../ContentControlTests.cs | 7 ++- .../DropDownTests.cs | 7 ++- .../ItemsControlTests.cs | 9 +-- .../TemplatedControlTests.cs | 13 +++-- .../FullLayoutTests.cs | 5 +- 12 files changed, 94 insertions(+), 90 deletions(-) create mode 100644 Perspex.Controls/Templates/TemplateExtensions.cs diff --git a/Perspex.Controls/ContentControl.cs b/Perspex.Controls/ContentControl.cs index 428e5292e4..e10a600a63 100644 --- a/Perspex.Controls/ContentControl.cs +++ b/Perspex.Controls/ContentControl.cs @@ -10,6 +10,7 @@ namespace Perspex.Controls using Perspex.Collections; using Perspex.Controls.Presenters; using Perspex.Controls.Primitives; + using Perspex.Controls.Templates; using Perspex.Layout; public class ContentControl : TemplatedControl, IContentControl, ILogical diff --git a/Perspex.Controls/ControlExtensions.cs b/Perspex.Controls/ControlExtensions.cs index c1211e1c5b..5eb2dc8a18 100644 --- a/Perspex.Controls/ControlExtensions.cs +++ b/Perspex.Controls/ControlExtensions.cs @@ -22,21 +22,5 @@ namespace Perspex.Controls .OfType() .FirstOrDefault(x => x.Id == id); } - - public static IEnumerable GetTemplateControls(this ITemplatedControl control) - { - var visual = control as IVisual; - - if (visual != null) - { - return visual.GetVisualDescendents() - .OfType() - .Where(x => x.TemplatedParent != null); - } - else - { - return Enumerable.Empty(); - } - } } } diff --git a/Perspex.Controls/DropDown.cs b/Perspex.Controls/DropDown.cs index 23d48fac8c..1a36bd9b34 100644 --- a/Perspex.Controls/DropDown.cs +++ b/Perspex.Controls/DropDown.cs @@ -10,6 +10,7 @@ namespace Perspex.Controls using Perspex.Collections; using Perspex.Controls.Presenters; using Perspex.Controls.Primitives; + using Perspex.Controls.Templates; using Perspex.Layout; public class DropDown : SelectingItemsControl, IContentControl, ILogical diff --git a/Perspex.Controls/ItemsControl.cs b/Perspex.Controls/ItemsControl.cs index 9893472505..ec19b52882 100644 --- a/Perspex.Controls/ItemsControl.cs +++ b/Perspex.Controls/ItemsControl.cs @@ -15,6 +15,7 @@ namespace Perspex.Controls using Perspex.Controls.Generators; using Perspex.Controls.Presenters; using Perspex.Controls.Primitives; + using Perspex.Controls.Templates; using Perspex.VisualTree; public class ItemsControl : TemplatedControl, ILogical @@ -87,10 +88,14 @@ namespace Perspex.Controls this.logicalChildren = null; } - this.presenter = this.GetTemplateChild("itemsPresenter"); - this.logicalChildren = new PerspexReadOnlyListView( - ((IVisual)presenter.Panel).VisualChildren, - x => (ILogical)x); + this.presenter = this.FindTemplateChild("itemsPresenter"); + + if (this.presenter != null) + { + this.logicalChildren = new PerspexReadOnlyListView( + ((IVisual)presenter.Panel).VisualChildren, + x => (ILogical)x); + } } private void ItemsChanged(Tuple value) diff --git a/Perspex.Controls/Perspex.Controls.csproj b/Perspex.Controls/Perspex.Controls.csproj index bf4b16a72b..f03f9d6434 100644 --- a/Perspex.Controls/Perspex.Controls.csproj +++ b/Perspex.Controls/Perspex.Controls.csproj @@ -85,6 +85,7 @@ + diff --git a/Perspex.Controls/Primitives/TemplatedControl.cs b/Perspex.Controls/Primitives/TemplatedControl.cs index 5eb78dbeb7..0b4ab5bda9 100644 --- a/Perspex.Controls/Primitives/TemplatedControl.cs +++ b/Perspex.Controls/Primitives/TemplatedControl.cs @@ -9,6 +9,7 @@ namespace Perspex.Controls.Primitives using System; using System.Linq; using Perspex.Controls.Presenters; + using Perspex.Controls.Templates; using Perspex.Media; using Perspex.Styling; using Perspex.VisualTree; @@ -122,7 +123,7 @@ namespace Perspex.Controls.Primitives this.AddVisualChild(child); child.Parent = this; - foreach (var i in this.GetTemplateControls()) + foreach (var i in this.GetTemplateChildren()) { i.ApplyTemplate(); } @@ -162,57 +163,6 @@ namespace Perspex.Controls.Primitives return new Size(); } - protected T FindTemplateChild(string id) where T : Control - { - var matches = this.GetTemplateControls() - .OfType() - .Where(x => x.Id == id) - .ToList(); - - if (matches.Count == 1) - { - return matches[0]; - } - else if (matches.Count == 0) - { - return null; - } - else - { - // If there are multiple matches, try filtering out nested matches. - matches = matches.Where(x => x.TemplatedParent == this).ToList(); - - if (matches.Count > 1) - { - throw new InvalidOperationException(string.Format( - "Found multiple template children '{0}' of type '{1}' in template for '{2}'.", - id, - typeof(T).FullName, - this.GetType().FullName)); - } - else - { - return matches.FirstOrDefault(); - } - } - } - - protected T GetTemplateChild(string id) where T : Control - { - var result = this.FindTemplateChild(id); - - if (result == null) - { - throw new InvalidOperationException(string.Format( - "Could not find template child '{0}' of type '{1}' in template for '{2}'.", - id, - typeof(T).FullName, - this.GetType().FullName)); - } - - return result; - } - protected virtual void OnTemplateApplied() { } diff --git a/Perspex.Controls/Templates/TemplateExtensions.cs b/Perspex.Controls/Templates/TemplateExtensions.cs new file mode 100644 index 0000000000..881aa98054 --- /dev/null +++ b/Perspex.Controls/Templates/TemplateExtensions.cs @@ -0,0 +1,57 @@ +// ----------------------------------------------------------------------- +// +// Copyright 2014 MIT Licence. See licence.md for more information. +// +// ----------------------------------------------------------------------- + +namespace Perspex.Controls.Templates +{ + using System; + using System.Collections.Generic; + using System.Linq; + using Perspex.Controls; + using Perspex.Styling; + using Perspex.VisualTree; + + public static class TemplateExtensions + { + public static T FindTemplateChild(this ITemplatedControl control, string id) where T : Control + { + return control.GetTemplateChildren().OfType().SingleOrDefault(x => x.Id == id); + } + + public static T GetTemplateChild(this ITemplatedControl control, string id) where T : Control + { + var result = control.FindTemplateChild(id); + + if (result == null) + { + throw new InvalidOperationException(string.Format( + "Could not find template child '{0}' of type '{1}' in template for '{2}'.", + id, + typeof(T).FullName, + control.GetType().FullName)); + } + + return result; + } + + public static IEnumerable GetTemplateChildren(this ITemplatedControl control) + { + var visual = control as IVisual; + + if (visual != null) + { + // TODO: This searches the whole descendent tree - it can stop when it exits the + // template. + return visual.GetVisualDescendents() + .OfType() + .Where(x => x.TemplatedParent == control); + } + else + { + return Enumerable.Empty(); + } + } + } +} diff --git a/Tests/Perspex.Controls.UnitTests/ContentControlTests.cs b/Tests/Perspex.Controls.UnitTests/ContentControlTests.cs index f76bc3d177..6a186c183b 100644 --- a/Tests/Perspex.Controls.UnitTests/ContentControlTests.cs +++ b/Tests/Perspex.Controls.UnitTests/ContentControlTests.cs @@ -12,6 +12,7 @@ namespace Perspex.Controls.UnitTests using Moq; using Perspex.Controls; using Perspex.Controls.Presenters; + using Perspex.Controls.Templates; using Perspex.Layout; using Perspex.Platform; using Perspex.Styling; @@ -173,7 +174,7 @@ namespace Perspex.Controls.UnitTests contentControl.ApplyTemplate(); // Need to call ApplyTemplate on presenter for CollectionChanged to be called. - var presenter = contentControl.GetTemplateControls().Single(x => x.Id == "contentPresenter"); + var presenter = contentControl.GetTemplateChildren().Single(x => x.Id == "contentPresenter"); presenter.ApplyTemplate(); Assert.True(called); @@ -196,7 +197,7 @@ namespace Perspex.Controls.UnitTests contentControl.Content = null; // Need to call ApplyTemplate on presenter for CollectionChanged to be called. - var presenter = contentControl.GetTemplateControls().Single(x => x.Id == "contentPresenter"); + var presenter = contentControl.GetTemplateChildren().Single(x => x.Id == "contentPresenter"); presenter.ApplyTemplate(); Assert.True(called); @@ -220,7 +221,7 @@ namespace Perspex.Controls.UnitTests contentControl.Content = child2; // Need to call ApplyTemplate on presenter for CollectionChanged to be called. - var presenter = contentControl.GetTemplateControls().Single(x => x.Id == "contentPresenter"); + var presenter = contentControl.GetTemplateChildren().Single(x => x.Id == "contentPresenter"); presenter.ApplyTemplate(); Assert.True(called); diff --git a/Tests/Perspex.Controls.UnitTests/DropDownTests.cs b/Tests/Perspex.Controls.UnitTests/DropDownTests.cs index 6f734c2ef0..182a756790 100644 --- a/Tests/Perspex.Controls.UnitTests/DropDownTests.cs +++ b/Tests/Perspex.Controls.UnitTests/DropDownTests.cs @@ -12,6 +12,7 @@ namespace Perspex.Controls.UnitTests using Moq; using Perspex.Controls; using Perspex.Controls.Presenters; + using Perspex.Controls.Templates; using Perspex.Platform; using Perspex.Styling; using Perspex.VisualTree; @@ -172,7 +173,7 @@ namespace Perspex.Controls.UnitTests target.ApplyTemplate(); // Need to call ApplyTemplate on presenter for CollectionChanged to be called. - var presenter = target.GetTemplateControls().Single(x => x.Id == "contentPresenter"); + var presenter = target.GetTemplateChildren().Single(x => x.Id == "contentPresenter"); presenter.ApplyTemplate(); Assert.True(called); @@ -195,7 +196,7 @@ namespace Perspex.Controls.UnitTests target.Content = null; // Need to call ApplyTemplate on presenter for CollectionChanged to be called. - var presenter = target.GetTemplateControls().Single(x => x.Id == "contentPresenter"); + var presenter = target.GetTemplateChildren().Single(x => x.Id == "contentPresenter"); presenter.ApplyTemplate(); Assert.True(called); @@ -219,7 +220,7 @@ namespace Perspex.Controls.UnitTests target.Content = child2; // Need to call ApplyTemplate on presenter for CollectionChanged to be called. - var presenter = target.GetTemplateControls().Single(x => x.Id == "contentPresenter"); + var presenter = target.GetTemplateChildren().Single(x => x.Id == "contentPresenter"); presenter.ApplyTemplate(); Assert.True(called); diff --git a/Tests/Perspex.Controls.UnitTests/ItemsControlTests.cs b/Tests/Perspex.Controls.UnitTests/ItemsControlTests.cs index 53e483a772..39905133e6 100644 --- a/Tests/Perspex.Controls.UnitTests/ItemsControlTests.cs +++ b/Tests/Perspex.Controls.UnitTests/ItemsControlTests.cs @@ -12,6 +12,7 @@ namespace Perspex.Controls.UnitTests using Perspex.Collections; using Perspex.Controls; using Perspex.Controls.Presenters; + using Perspex.Controls.Templates; using Perspex.Platform; using Perspex.Styling; using Perspex.VisualTree; @@ -31,8 +32,8 @@ namespace Perspex.Controls.UnitTests target.Items = new[] { "Foo" }; target.ApplyTemplate(); - var presenter = target.GetTemplateControls().OfType().Single(); - var panel = presenter.GetTemplateControls().OfType().Single(); + var presenter = target.GetTemplateChildren().OfType().Single(); + var panel = presenter.GetTemplateChildren().OfType().Single(); Assert.Equal(presenter, panel.TemplatedParent); } @@ -46,8 +47,8 @@ namespace Perspex.Controls.UnitTests target.Items = new[] { "Foo" }; target.ApplyTemplate(); - var presenter = target.GetTemplateControls().OfType().Single(); - var panel = presenter.GetTemplateControls().OfType().Single(); + var presenter = target.GetTemplateChildren().OfType().Single(); + var panel = presenter.GetTemplateChildren().OfType().Single(); var item = (TextBlock)panel.GetVisualChildren().First(); Assert.Null(item.TemplatedParent); diff --git a/Tests/Perspex.Controls.UnitTests/TemplatedControlTests.cs b/Tests/Perspex.Controls.UnitTests/TemplatedControlTests.cs index 51111ee44b..3348ac77da 100644 --- a/Tests/Perspex.Controls.UnitTests/TemplatedControlTests.cs +++ b/Tests/Perspex.Controls.UnitTests/TemplatedControlTests.cs @@ -11,6 +11,7 @@ namespace Perspex.Controls.UnitTests using Perspex.Controls; using Perspex.Controls.Presenters; using Perspex.Controls.Primitives; + using Perspex.Controls.Templates; using Perspex.Styling; using Perspex.VisualTree; using Splat; @@ -201,8 +202,8 @@ namespace Perspex.Controls.UnitTests target.ApplyTemplate(); - var panel = target.GetTemplateControls().OfType().Single(); - var textBlock = target.GetTemplateControls().OfType().Single(); + var panel = target.GetTemplateChildren().OfType().Single(); + var textBlock = target.GetTemplateChildren().OfType().Single(); Assert.Equal(target, panel.TemplatedParent); Assert.Equal(target, textBlock.TemplatedParent); @@ -226,7 +227,7 @@ namespace Perspex.Controls.UnitTests target.ApplyTemplate(); - var presenter = target.GetTemplateControls().OfType().Single(); + var presenter = target.GetTemplateChildren().OfType().Single(); var textBlock = (TextBlock)presenter.Child; Assert.Equal(target, presenter.TemplatedParent); @@ -261,9 +262,9 @@ namespace Perspex.Controls.UnitTests target.ApplyTemplate(); - var contentControl = target.GetTemplateControls().OfType().Single(); - var border = contentControl.GetTemplateControls().OfType().Single(); - var presenter = contentControl.GetTemplateControls().OfType().Single(); + var contentControl = target.GetTemplateChildren().OfType().Single(); + var border = contentControl.GetTemplateChildren().OfType().Single(); + var presenter = contentControl.GetTemplateChildren().OfType().Single(); var textBlock = (TextBlock)presenter.Content; Assert.Equal(target, contentControl.TemplatedParent); diff --git a/Tests/Perspex.Layout.UnitTests/FullLayoutTests.cs b/Tests/Perspex.Layout.UnitTests/FullLayoutTests.cs index ad77307788..5acaa67c9c 100644 --- a/Tests/Perspex.Layout.UnitTests/FullLayoutTests.cs +++ b/Tests/Perspex.Layout.UnitTests/FullLayoutTests.cs @@ -11,6 +11,7 @@ namespace Perspex.Layout.UnitTests using Perspex.Controls; using Perspex.Controls.Presenters; using Perspex.Controls.Primitives; + using Perspex.Controls.Templates; using Perspex.Input; using Perspex.Platform; using Perspex.Rendering; @@ -98,8 +99,8 @@ namespace Perspex.Layout.UnitTests Assert.Equal(new Point(300, 200), Position(scrollViewer)); Assert.Equal(new Size(400, 400), textBlock.ActualSize); - var scrollBars = scrollViewer.GetTemplateControls().OfType().ToList(); - var presenters = scrollViewer.GetTemplateControls().OfType().ToList(); + var scrollBars = scrollViewer.GetTemplateChildren().OfType().ToList(); + var presenters = scrollViewer.GetTemplateChildren().OfType().ToList(); Assert.Equal(2, scrollBars.Count); Assert.Equal(1, presenters.Count);