// Copyright (c) The Avalonia Project. All rights reserved. // Licensed under the MIT license. See licence.md file in the project root for full license information. using Avalonia.Controls.Primitives; using Avalonia.Controls.Templates; using Avalonia.Input; using Avalonia.Interactivity; using Avalonia.Rendering; using Avalonia.Styling; using Avalonia.VisualTree; namespace Avalonia.Controls { /// /// Base class for Avalonia controls. /// /// /// The control class extends and adds the following features: /// /// - A property to allow user-defined data to be attached to the control. /// public class Control : InputElement, IControl, INamed, ISupportInitialize, IVisualBrushInitialize, IRequiresTemplateInSetter { /// /// Defines the property. /// public static readonly StyledProperty> FocusAdornerProperty = AvaloniaProperty.Register>(nameof(FocusAdorner)); /// /// Defines the property. /// public static readonly StyledProperty TagProperty = AvaloniaProperty.Register(nameof(Tag)); /// /// Defines the property. /// public static readonly StyledProperty ContextMenuProperty = AvaloniaProperty.Register(nameof(ContextMenu)); /// /// Event raised when an element wishes to be scrolled into view. /// public static readonly RoutedEvent RequestBringIntoViewEvent = RoutedEvent.Register("RequestBringIntoView", RoutingStrategies.Bubble); private DataTemplates _dataTemplates; private IControl _focusAdorner; /// /// Gets or sets the control's focus adorner. /// public ITemplate FocusAdorner { get { return GetValue(FocusAdornerProperty); } set { SetValue(FocusAdornerProperty, value); } } /// /// Gets or sets the data templates for the control. /// /// /// Each control may define data templates which are applied to the control itself and its /// children. /// public DataTemplates DataTemplates => _dataTemplates ?? (_dataTemplates = new DataTemplates()); /// /// Gets or sets a context menu to the control. /// public ContextMenu ContextMenu { get { return GetValue(ContextMenuProperty); } set { SetValue(ContextMenuProperty, value); } } /// /// Gets or sets a user-defined object attached to the control. /// public object Tag { get { return GetValue(TagProperty); } set { SetValue(TagProperty, value); } } public new IControl Parent => (IControl)base.Parent; /// bool IDataTemplateHost.IsDataTemplatesInitialized => _dataTemplates != null; /// void IVisualBrushInitialize.EnsureInitialized() { if (VisualRoot == null) { if (!IsInitialized) { foreach (var i in this.GetSelfAndVisualDescendants()) { var c = i as IControl; if (c?.IsInitialized == false) { var init = c as ISupportInitialize; if (init != null) { init.BeginInit(); init.EndInit(); } } } } if (!IsArrangeValid) { Measure(Size.Infinity); Arrange(new Rect(DesiredSize)); } } } /// /// Gets the element that receives the focus adorner. /// /// The control that receives the focus adorner. protected virtual IControl GetTemplateFocusTarget() { return this; } /// protected sealed override void OnAttachedToVisualTreeCore(VisualTreeAttachmentEventArgs e) { base.OnAttachedToVisualTreeCore(e); InitializeIfNeeded(); } /// protected sealed override void OnDetachedFromVisualTreeCore(VisualTreeAttachmentEventArgs e) { base.OnDetachedFromVisualTreeCore(e); } /// protected override void OnGotFocus(GotFocusEventArgs e) { base.OnGotFocus(e); if (IsFocused && (e.NavigationMethod == NavigationMethod.Tab || e.NavigationMethod == NavigationMethod.Directional)) { var adornerLayer = AdornerLayer.GetAdornerLayer(this); if (adornerLayer != null) { if (_focusAdorner == null) { var template = GetValue(FocusAdornerProperty); if (template != null) { _focusAdorner = template.Build(); } } if (_focusAdorner != null) { var target = (Visual)GetTemplateFocusTarget(); if (target != null) { AdornerLayer.SetAdornedElement((Visual)_focusAdorner, target); adornerLayer.Children.Add(_focusAdorner); } } } } } /// protected override void OnLostFocus(RoutedEventArgs e) { base.OnLostFocus(e); if (_focusAdorner != null) { var adornerLayer = (IPanel)_focusAdorner.Parent; adornerLayer.Children.Remove(_focusAdorner); _focusAdorner = null; } } } }