From 01c7d028d04ff0bb705a1e559954dd48f5f24828 Mon Sep 17 00:00:00 2001 From: Steven Kirk Date: Thu, 11 Dec 2014 23:46:55 +0100 Subject: [PATCH] Correctly apply nested templates. When a templated control's template itself contains templated controls, make sure all of the templates are applied, as the nested templated control might contain something the top-most templated control is looking for. --- Perspex.Controls/ControlExtensions.cs | 4 +-- Perspex.Controls/ControlTemplate.cs | 2 ++ .../Presenters/ContentPresenter.cs | 2 +- Perspex.Controls/Presenters/ItemsPresenter.cs | 2 +- .../Primitives/TemplatedControl.cs | 27 +++++++++++++++++-- Perspex.Controls/TextBox.cs | 12 +-------- Perspex.Layout/Layoutable.cs | 8 +++--- 7 files changed, 36 insertions(+), 21 deletions(-) diff --git a/Perspex.Controls/ControlExtensions.cs b/Perspex.Controls/ControlExtensions.cs index bfed08f51e..437aff1983 100644 --- a/Perspex.Controls/ControlExtensions.cs +++ b/Perspex.Controls/ControlExtensions.cs @@ -31,9 +31,9 @@ namespace Perspex.Controls { IVisual visual = parent as IVisual; - foreach (IVisual child in visual.VisualChildren.OfType().Where(x => x.TemplatedParent == templated)) + foreach (var child in visual.VisualChildren.OfType().Where(x => x.TemplatedParent != null)) { - yield return (Control)child; + yield return child; foreach (IVisual grandchild in GetTemplateControls(templated, child)) { diff --git a/Perspex.Controls/ControlTemplate.cs b/Perspex.Controls/ControlTemplate.cs index 95b80c7814..4549da6844 100644 --- a/Perspex.Controls/ControlTemplate.cs +++ b/Perspex.Controls/ControlTemplate.cs @@ -7,6 +7,8 @@ namespace Perspex.Controls { using System; + using System.Linq; + using Perspex.Layout; using Perspex.Styling; public class ControlTemplate diff --git a/Perspex.Controls/Presenters/ContentPresenter.cs b/Perspex.Controls/Presenters/ContentPresenter.cs index fb233d4aa2..617489ad67 100644 --- a/Perspex.Controls/Presenters/ContentPresenter.cs +++ b/Perspex.Controls/Presenters/ContentPresenter.cs @@ -30,7 +30,7 @@ namespace Perspex.Controls.Presenters set { this.SetValue(ContentProperty, value); } } - protected override sealed void ApplyTemplate() + public override sealed void ApplyTemplate() { if (!this.createdChild) { diff --git a/Perspex.Controls/Presenters/ItemsPresenter.cs b/Perspex.Controls/Presenters/ItemsPresenter.cs index 622e3b9e9d..8830122696 100644 --- a/Perspex.Controls/Presenters/ItemsPresenter.cs +++ b/Perspex.Controls/Presenters/ItemsPresenter.cs @@ -41,7 +41,7 @@ namespace Perspex.Controls.Presenters set { this.SetValue(ItemsPanelProperty, value); } } - protected override sealed void ApplyTemplate() + public override sealed void ApplyTemplate() { if (!this.createdPanel) { diff --git a/Perspex.Controls/Primitives/TemplatedControl.cs b/Perspex.Controls/Primitives/TemplatedControl.cs index 90d305f4f8..a6bf3bcc4e 100644 --- a/Perspex.Controls/Primitives/TemplatedControl.cs +++ b/Perspex.Controls/Primitives/TemplatedControl.cs @@ -20,6 +20,16 @@ namespace Perspex.Controls.Primitives private bool templateApplied; + static TemplatedControl() + { + TemplateProperty.Changed.Subscribe(e => + { + var templatedControl = (TemplatedControl)e.Sender; + templatedControl.templateApplied = false; + templatedControl.InvalidateMeasure(); + }); + } + public ControlTemplate Template { get { return this.GetValue(TemplateProperty); } @@ -30,7 +40,7 @@ namespace Perspex.Controls.Primitives { } - protected override void ApplyTemplate() + public sealed override void ApplyTemplate() { if (!this.templateApplied) { @@ -45,6 +55,17 @@ namespace Perspex.Controls.Primitives var child = this.Template.Build(this); this.AddVisualChild(child); + + var templateChildren = this.GetVisualDescendents() + .OfType() + .Where(x => x.TemplatedParent != null); + + foreach (var i in templateChildren) + { + i.ApplyTemplate(); + } + + this.OnTemplateApplied(); } @@ -82,7 +103,9 @@ namespace Perspex.Controls.Primitives protected T FindTemplateChild(string id) where T : Control { - return this.GetTemplateControls().OfType().FirstOrDefault(x => x.Id == id); + return this.GetTemplateControls() + .Where(x => x.TemplatedParent == this) + .OfType().FirstOrDefault(x => x.Id == id); } protected T GetTemplateChild(string id) where T : Control diff --git a/Perspex.Controls/TextBox.cs b/Perspex.Controls/TextBox.cs index 6b6fe20ddf..6920677b41 100644 --- a/Perspex.Controls/TextBox.cs +++ b/Perspex.Controls/TextBox.cs @@ -141,17 +141,7 @@ namespace Perspex.Controls protected override void OnTemplateApplied() { - Decorator textContainer = this.GetVisualDescendents() - .OfType() - .FirstOrDefault(x => x.Id == "textContainer"); - - if (textContainer == null) - { - throw new Exception( - "TextBox template doesn't contain a textContainer " + - "or textContainer is not a Decorator."); - } - + Decorator textContainer = this.GetTemplateChild("textContainer"); textContainer.Content = this.textBoxView = new TextBoxView(this); } diff --git a/Perspex.Layout/Layoutable.cs b/Perspex.Layout/Layoutable.cs index d1d0b1d57c..69f1277388 100644 --- a/Perspex.Layout/Layoutable.cs +++ b/Perspex.Layout/Layoutable.cs @@ -163,6 +163,10 @@ namespace Perspex.Layout get { return this.previousArrange; } } + public virtual void ApplyTemplate() + { + } + public void Measure(Size availableSize, bool force = false) { if (double.IsNaN(availableSize.Width) || double.IsNaN(availableSize.Height)) @@ -259,10 +263,6 @@ namespace Perspex.Layout property.Changed.Subscribe(AffectsMeasureInvalidate); } - protected virtual void ApplyTemplate() - { - } - protected virtual void ArrangeCore(Rect finalRect) { if (this.IsVisible)