// ----------------------------------------------------------------------- // // Copyright 2014 MIT Licence. See licence.md for more information. // // ----------------------------------------------------------------------- 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; using Serilog; using Serilog.Core.Enrichers; /// /// A lookless control whose visual appearance is defined by its . /// public class TemplatedControl : Control, ITemplatedControl { /// /// Defines the property. /// public static readonly PerspexProperty BackgroundProperty = Border.BackgroundProperty.AddOwner(); /// /// Defines the property. /// public static readonly PerspexProperty BorderBrushProperty = Border.BorderBrushProperty.AddOwner(); /// /// Defines the property. /// public static readonly PerspexProperty BorderThicknessProperty = Border.BorderThicknessProperty.AddOwner(); /// /// Defines the property. /// public static readonly PerspexProperty FontFamilyProperty = TextBlock.FontFamilyProperty.AddOwner(); /// /// Defines the property. /// public static readonly PerspexProperty FontSizeProperty = TextBlock.FontSizeProperty.AddOwner(); /// /// Defines the property. /// public static readonly PerspexProperty FontStyleProperty = TextBlock.FontStyleProperty.AddOwner(); /// /// Defines the property. /// public static readonly PerspexProperty ForegroundProperty = TextBlock.ForegroundProperty.AddOwner(); /// /// Defines the property. /// public static readonly PerspexProperty PaddingProperty = Decorator.PaddingProperty.AddOwner(); /// /// Defines the property. /// public static readonly PerspexProperty TemplateProperty = PerspexProperty.Register("Template"); private bool templateApplied; private ILogger templateLog; /// /// Initializes static members of the class. /// static TemplatedControl() { TemplateProperty.Changed.Subscribe(e => { var templatedControl = (TemplatedControl)e.Sender; templatedControl.templateApplied = false; templatedControl.InvalidateMeasure(); }); } /// /// Initializes a new instance of the class. /// public TemplatedControl() { this.templateLog = Log.ForContext(new[] { new PropertyEnricher("Area", "Template"), new PropertyEnricher("SourceContext", this.GetType()), new PropertyEnricher("Id", this.GetHashCode()), }); } /// /// Gets or sets the brush used to draw the control's background. /// public Brush Background { get { return this.GetValue(BackgroundProperty); } set { this.SetValue(BackgroundProperty, value); } } /// /// Gets or sets the brush used to draw the control's border. /// public Brush BorderBrush { get { return this.GetValue(BorderBrushProperty); } set { this.SetValue(BorderBrushProperty, value); } } /// /// Gets or sets the thickness of the control's border. /// public double BorderThickness { get { return this.GetValue(BorderThicknessProperty); } set { this.SetValue(BorderThicknessProperty, value); } } /// /// Gets or sets the font family used to draw the control's text. /// public string FontFamily { get { return this.GetValue(FontFamilyProperty); } set { this.SetValue(FontFamilyProperty, value); } } /// /// Gets or sets the size of the control's text in points. /// public double FontSize { get { return this.GetValue(FontSizeProperty); } set { this.SetValue(FontSizeProperty, value); } } /// /// Gets or sets the font style used to draw the control's text. /// public FontStyle FontStyle { get { return this.GetValue(FontStyleProperty); } set { this.SetValue(FontStyleProperty, value); } } /// /// Gets or sets the brush used to draw the control's text and other foreground elements. /// public Brush Foreground { get { return this.GetValue(ForegroundProperty); } set { this.SetValue(ForegroundProperty, value); } } /// /// Gets or sets the padding placed between the border of the control and its content. /// public Thickness Padding { get { return this.GetValue(PaddingProperty); } set { this.SetValue(PaddingProperty, value); } } /// /// Gets or sets the template that defines the control's appearance. /// public ControlTemplate Template { get { return this.GetValue(TemplateProperty); } set { this.SetValue(TemplateProperty, value); } } /// public sealed override void ApplyTemplate() { if (!this.templateApplied) { this.ClearVisualChildren(); if (this.Template != null) { this.templateLog.Verbose("Creating control template"); var child = this.Template.Build(this); // We need to call this twice - once before the controls are added to the // visual tree so that the logical tree can be set up before styling is // applied. this.SetTemplatedParentAndApplyChildTemplates(child); this.AddVisualChild((Visual)child); ((ISetLogicalParent)child).SetParent(this); // And again after the controls are added to the visual tree, and have their // styling and thus Template property set. this.SetTemplatedParentAndApplyChildTemplates(child); this.OnTemplateApplied(); } this.templateApplied = true; } } /// /// Called when the control's template is applied. /// protected virtual void OnTemplateApplied() { } /// /// Sets the TemplatedParent property for a control created from the control template and /// applies the templates of nested templated controls. /// /// The control. private void SetTemplatedParentAndApplyChildTemplates(IControl control) { if (control.TemplatedParent == null) { control.SetValue(TemplatedParentProperty, this); } control.ApplyTemplate(); if (!(control is IPresenter && control.TemplatedParent == this)) { foreach (IControl child in control.GetVisualChildren()) { this.SetTemplatedParentAndApplyChildTemplates(child); } } } } }