// 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;
}
}
}
}