diff --git a/Perspex.Controls/Button.cs b/Perspex.Controls/Button.cs index 4c418a347e..cb797c77b8 100644 --- a/Perspex.Controls/Button.cs +++ b/Perspex.Controls/Button.cs @@ -102,6 +102,8 @@ namespace Perspex.Controls protected override void OnDetachedFromVisualTree(IRenderRoot oldRoot) { + base.OnDetachedFromVisualTree(oldRoot); + if (this.IsDefault) { var inputElement = oldRoot as IInputElement; diff --git a/Perspex.Controls/Control.cs b/Perspex.Controls/Control.cs index dbc0762d3d..40f50695aa 100644 --- a/Perspex.Controls/Control.cs +++ b/Perspex.Controls/Control.cs @@ -218,7 +218,7 @@ namespace Perspex.Controls if (this.focusAdorner != null) { - var adornerLayer = AdornerLayer.GetAdornerLayer(this); + var adornerLayer = this.focusAdorner.Parent as Panel; adornerLayer.Children.Remove(this.focusAdorner); this.focusAdorner = null; } diff --git a/Perspex.Input/FocusManager.cs b/Perspex.Input/FocusManager.cs index 64a8ec84d4..9750c05cff 100644 --- a/Perspex.Input/FocusManager.cs +++ b/Perspex.Input/FocusManager.cs @@ -44,44 +44,66 @@ namespace Perspex.Input /// public void Focus(IInputElement control, bool keyboardNavigated = false) { - Contract.Requires(control != null); + if (control != null) + { + var scope = control.GetSelfAndVisualAncestors() + .OfType() + .FirstOrDefault(); - var current = this.Current as IInteractive; - var next = control as IInteractive; - var scope = control.GetSelfAndVisualAncestors() - .OfType() - .FirstOrDefault(); + if (scope != null) + { + this.SetFocusedElement(scope, control, keyboardNavigated); + } + } + else + { + this.SetFocusedElement(this.Scope, null); + } + } - if (scope != null && control != current) + /// + /// Sets the currently focused element in the specified scope. + /// + /// The focus scope. + /// The element to focus. May be null. + /// + /// Whether the control was focused by a keypress (e.g. the Tab key). + /// + /// + /// If the specified scope is the current then the keyboard focus + /// will change. + /// + public void SetFocusedElement( + IFocusScope scope, + IInputElement element, + bool keyboardNavigated = false) + { + Contract.Requires(scope != null); + + this.focusScopes[scope] = element; + + if (this.Scope == scope) { - this.focusScopes[scope] = control; + var interactive = this.Current as IInteractive; - if (current != null) + if (interactive != null) { - current.RaiseEvent(new RoutedEventArgs + interactive.RaiseEvent(new RoutedEventArgs { RoutedEvent = InputElement.LostFocusEvent, - Source = current, - OriginalSource = current, }); } - this.Current = control; + this.Current = element; + KeyboardDevice.Instance.FocusedElement = element; - IKeyboardDevice keyboard = Locator.Current.GetService(); + interactive = element as IInteractive; - if (keyboard != null) + if (interactive != null) { - keyboard.FocusedElement = control; - } - - if (next != null) - { - next.RaiseEvent(new GotFocusEventArgs + interactive.RaiseEvent(new GotFocusEventArgs { RoutedEvent = InputElement.GotFocusEvent, - Source = next, - OriginalSource = next, KeyboardNavigated = keyboardNavigated, }); } @@ -92,10 +114,6 @@ namespace Perspex.Input /// Notifies the focus manager of a change in focus scope. /// /// The new focus scope. - /// - /// This should not be called by client code. It is called by an - /// when it activates, e.g. when a Window is activated. - /// public void SetFocusScope(IFocusScope scope) { Contract.Requires(scope != null); diff --git a/Perspex.Input/InputElement.cs b/Perspex.Input/InputElement.cs index cc7c9cf740..b364f443e2 100644 --- a/Perspex.Input/InputElement.cs +++ b/Perspex.Input/InputElement.cs @@ -9,6 +9,7 @@ namespace Perspex.Input using System; using System.Linq; using Perspex.Interactivity; + using Perspex.Rendering; using Perspex.VisualTree; public class InputElement : Interactive, IInputElement @@ -196,6 +197,16 @@ namespace Perspex.Input FocusManager.Instance.Focus(this); } + protected override void OnDetachedFromVisualTree(IRenderRoot oldRoot) + { + base.OnDetachedFromVisualTree(oldRoot); + + if (this.IsFocused) + { + FocusManager.Instance.Focus(null); + } + } + protected override void OnVisualParentChanged(Visual oldParent) { this.UpdateIsEnabledCore(); diff --git a/Perspex.Input/KeyboardDevice.cs b/Perspex.Input/KeyboardDevice.cs index e9f37d3efa..9a7dea13c6 100644 --- a/Perspex.Input/KeyboardDevice.cs +++ b/Perspex.Input/KeyboardDevice.cs @@ -22,6 +22,11 @@ namespace Perspex.Input .Subscribe(this.ProcessRawEvent); } + public static IKeyboardDevice Instance + { + get { return Locator.Current.GetService(); } + } + public IInputManager InputManager { get { return Locator.Current.GetService(); }