diff --git a/Perspex.Controls/Control.cs b/Perspex.Controls/Control.cs index 7cc3545838..8b98f0fd7e 100644 --- a/Perspex.Controls/Control.cs +++ b/Perspex.Controls/Control.cs @@ -355,7 +355,7 @@ namespace Perspex.Controls { base.OnGotFocus(e); - if (this.IsFocused && e.KeyboardNavigated) + if (this.IsFocused && e.NavigationMethod == NavigationMethod.Tab) { var adornerLayer = AdornerLayer.GetAdornerLayer(this); diff --git a/Perspex.Controls/Primitives/SelectingItemsControl.cs b/Perspex.Controls/Primitives/SelectingItemsControl.cs index b73e13947f..c1c9bf7454 100644 --- a/Perspex.Controls/Primitives/SelectingItemsControl.cs +++ b/Perspex.Controls/Primitives/SelectingItemsControl.cs @@ -159,7 +159,19 @@ namespace Perspex.Controls.Primitives protected override void OnGotFocus(GotFocusEventArgs e) { base.OnGotFocus(e); - this.TrySetSelectionFromContainerEvent(e.Source, true); + + if (e.NavigationMethod == NavigationMethod.Pointer || + e.NavigationMethod == NavigationMethod.Directional) + { + this.TrySetSelectionFromContainerEvent(e.Source, true); + } + } + + /// + protected override void OnPointerPressed(PointerPressEventArgs e) + { + base.OnPointerPressed(e); + e.Handled = true; } /// diff --git a/Perspex.Input/FocusManager.cs b/Perspex.Input/FocusManager.cs index 2be4f28ebc..1baa6b022f 100644 --- a/Perspex.Input/FocusManager.cs +++ b/Perspex.Input/FocusManager.cs @@ -65,10 +65,8 @@ namespace Perspex.Input /// Focuses a control. /// /// The control to focus. - /// - /// Whether the control was focused by a keypress (e.g. the Tab key). - /// - public void Focus(IInputElement control, bool keyboardNavigated = false) + /// The method by which focus was changed. + public void Focus(IInputElement control, NavigationMethod method = NavigationMethod.Unspecified) { if (control != null) { @@ -78,7 +76,7 @@ namespace Perspex.Input if (scope != null) { this.Scope = scope; - this.SetFocusedElement(scope, control, keyboardNavigated); + this.SetFocusedElement(scope, control, method); } } else if (this.Current != null) @@ -90,7 +88,7 @@ namespace Perspex.Input if (this.focusScopes.TryGetValue(scope, out element)) { - this.Focus(element, keyboardNavigated); + this.Focus(element, method); break; } } @@ -102,9 +100,7 @@ namespace Perspex.Input /// /// The focus scope. /// The element to focus. May be null. - /// - /// Whether the control was focused by a keypress (e.g. the Tab key). - /// + /// The method by which focus was changed. /// /// If the specified scope is the current then the keyboard focus /// will change. @@ -112,7 +108,7 @@ namespace Perspex.Input public void SetFocusedElement( IFocusScope scope, IInputElement element, - bool keyboardNavigated = false) + NavigationMethod method = NavigationMethod.Unspecified) { Contract.Requires(scope != null); @@ -120,7 +116,7 @@ namespace Perspex.Input if (this.Scope == scope) { - KeyboardDevice.Instance.SetFocusedElement(element, keyboardNavigated); + KeyboardDevice.Instance.SetFocusedElement(element, method); } } @@ -196,7 +192,7 @@ namespace Perspex.Input if (element != null) { - this.Focus(element); + this.Focus(element, NavigationMethod.Pointer); } } } diff --git a/Perspex.Input/GotFocusEventArgs.cs b/Perspex.Input/GotFocusEventArgs.cs index bf393ed4d1..cf7cd12bde 100644 --- a/Perspex.Input/GotFocusEventArgs.cs +++ b/Perspex.Input/GotFocusEventArgs.cs @@ -8,12 +8,14 @@ namespace Perspex.Input { using Perspex.Interactivity; + /// + /// Holds arguments for a . + /// public class GotFocusEventArgs : RoutedEventArgs { /// - /// Gets or sets a value indicating whether the control was focused by a keypress (e.g. - /// the Tab key). + /// Gets or sets a value indicating how the change in focus occurred. /// - public bool KeyboardNavigated { get; set; } + public NavigationMethod NavigationMethod { get; set; } } } diff --git a/Perspex.Input/IFocusManager.cs b/Perspex.Input/IFocusManager.cs index 8b67ad19c4..3a82a2abca 100644 --- a/Perspex.Input/IFocusManager.cs +++ b/Perspex.Input/IFocusManager.cs @@ -22,10 +22,8 @@ namespace Perspex.Input /// Focuses a control. /// /// The control to focus. - /// - /// Whether the control was focused by a keypress (e.g. the Tab key). - /// - void Focus(IInputElement focusable, bool keyboardNavigated = false); + /// The method by which focus was changed. + void Focus(IInputElement control, NavigationMethod method = NavigationMethod.Unspecified); /// /// Notifies the focus manager of a change in focus scope. diff --git a/Perspex.Input/IKeyboardDevice.cs b/Perspex.Input/IKeyboardDevice.cs index a43fb0cd2a..71bed251a9 100644 --- a/Perspex.Input/IKeyboardDevice.cs +++ b/Perspex.Input/IKeyboardDevice.cs @@ -32,6 +32,6 @@ namespace Perspex.Input ModifierKeys Modifiers { get; } - void SetFocusedElement(IInputElement element, bool keyboardNavigated); + void SetFocusedElement(IInputElement element, NavigationMethod method); } } diff --git a/Perspex.Input/InputElement.cs b/Perspex.Input/InputElement.cs index b80e3f24a1..bc83f47607 100644 --- a/Perspex.Input/InputElement.cs +++ b/Perspex.Input/InputElement.cs @@ -228,7 +228,7 @@ namespace Perspex.Input protected virtual void OnGotFocus(GotFocusEventArgs e) { this.IsFocused = e.OriginalSource == this; - this.SetValue(IsTabFocusedProperty, e.KeyboardNavigated); + this.SetValue(IsTabFocusedProperty, e.NavigationMethod == NavigationMethod.Tab); } protected virtual void OnLostFocus(RoutedEventArgs e) diff --git a/Perspex.Input/KeyboardDevice.cs b/Perspex.Input/KeyboardDevice.cs index 6758cbbd0b..3dfc451171 100644 --- a/Perspex.Input/KeyboardDevice.cs +++ b/Perspex.Input/KeyboardDevice.cs @@ -60,7 +60,7 @@ namespace Perspex.Input public abstract ModifierKeys Modifiers { get; } - public void SetFocusedElement(IInputElement element, bool keyboardNavigated) + public void SetFocusedElement(IInputElement element, NavigationMethod method) { if (element != this.FocusedElement) { @@ -82,7 +82,7 @@ namespace Perspex.Input interactive.RaiseEvent(new GotFocusEventArgs { RoutedEvent = InputElement.GotFocusEvent, - KeyboardNavigated = keyboardNavigated, + NavigationMethod = method, }); } } diff --git a/Perspex.Input/KeyboardNavigationHandler.cs b/Perspex.Input/KeyboardNavigationHandler.cs index 196cdab107..175a9ee4ed 100644 --- a/Perspex.Input/KeyboardNavigationHandler.cs +++ b/Perspex.Input/KeyboardNavigationHandler.cs @@ -78,7 +78,10 @@ namespace Perspex.Input if (next != null) { - FocusManager.Instance.Focus(next, true); + var method = direction == FocusNavigationDirection.Next || + direction == FocusNavigationDirection.Previous ? + NavigationMethod.Tab : NavigationMethod.Directional; + FocusManager.Instance.Focus(next, method); } } diff --git a/Perspex.Input/NavigationMethod.cs b/Perspex.Input/NavigationMethod.cs new file mode 100644 index 0000000000..a4c2d75c83 --- /dev/null +++ b/Perspex.Input/NavigationMethod.cs @@ -0,0 +1,35 @@ +// ----------------------------------------------------------------------- +// +// Copyright 2015 MIT Licence. See licence.md for more information. +// +// ----------------------------------------------------------------------- + +namespace Perspex.Input +{ + /// + /// Defines the method by which a focus change occurred. + /// + public enum NavigationMethod + { + /// + /// The focus was changed by an unspecified method, e.g. calling + /// . + /// + Unspecified, + + /// + /// The focus was changed by the user tabbing between control. + /// + Tab, + + /// + /// The focus was changed by the user pressing a directional navigation key. + /// + Directional, + + /// + /// The focus was changed by a pointer click. + /// + Pointer, + } +} diff --git a/Perspex.Input/Perspex.Input.csproj b/Perspex.Input/Perspex.Input.csproj index bb20879f6b..aab6e3a5e3 100644 --- a/Perspex.Input/Perspex.Input.csproj +++ b/Perspex.Input/Perspex.Input.csproj @@ -61,6 +61,7 @@ + diff --git a/TestApplication/Program.cs b/TestApplication/Program.cs index 26fc19e3cf..c58618bf60 100644 --- a/TestApplication/Program.cs +++ b/TestApplication/Program.cs @@ -492,7 +492,6 @@ namespace TestApplication (listBox = new ListBox { Items = listBoxData, - SelectedIndex = 0, MaxHeight = 300, }), new DropDown diff --git a/Tests/Perspex.Controls.UnitTests/Primitives/SelectingItemsControlTests.cs b/Tests/Perspex.Controls.UnitTests/Primitives/SelectingItemsControlTests.cs index f45cf4f664..d0ac23e29a 100644 --- a/Tests/Perspex.Controls.UnitTests/Primitives/SelectingItemsControlTests.cs +++ b/Tests/Perspex.Controls.UnitTests/Primitives/SelectingItemsControlTests.cs @@ -334,7 +334,7 @@ namespace Perspex.Controls.UnitTests.Primitives } [Fact] - public void Focusing_Item_Should_Select_It() + public void Focusing_Item_With_Pointer_Should_Select_It() { var target = new SelectingItemsControl { @@ -346,7 +346,33 @@ namespace Perspex.Controls.UnitTests.Primitives var e = new GotFocusEventArgs { - RoutedEvent = InputElement.GotFocusEvent + RoutedEvent = InputElement.GotFocusEvent, + NavigationMethod = NavigationMethod.Pointer, + }; + + target.Presenter.Panel.Children[1].RaiseEvent(e); + + Assert.Equal(1, target.SelectedIndex); + + // GotFocus should be raised on parent control. + Assert.False(e.Handled); + } + + [Fact] + public void Focusing_Item_With_Directional_Keys_Should_Select_It() + { + var target = new SelectingItemsControl + { + Template = this.Template(), + Items = new[] { "foo", "bar" }, + }; + + target.ApplyTemplate(); + + var e = new GotFocusEventArgs + { + RoutedEvent = InputElement.GotFocusEvent, + NavigationMethod = NavigationMethod.Directional, }; target.Presenter.Panel.Children[1].RaiseEvent(e); @@ -355,6 +381,28 @@ namespace Perspex.Controls.UnitTests.Primitives Assert.False(e.Handled); } + [Fact] + public void Focusing_Item_With_Tab_Should_Not_Select_It() + { + var target = new SelectingItemsControl + { + Template = this.Template(), + Items = new[] { "foo", "bar" }, + }; + + target.ApplyTemplate(); + + var e = new GotFocusEventArgs + { + RoutedEvent = InputElement.GotFocusEvent, + NavigationMethod = NavigationMethod.Tab, + }; + + target.Presenter.Panel.Children[1].RaiseEvent(e); + + Assert.Equal(-1, target.SelectedIndex); + } + [Fact] public void Raising_IsSelectedChanged_On_Item_Should_Update_Selection() { diff --git a/Windows/Perspex.Win32/Input/WindowsKeyboardDevice.cs b/Windows/Perspex.Win32/Input/WindowsKeyboardDevice.cs index c2162f035a..ab01df1f05 100644 --- a/Windows/Perspex.Win32/Input/WindowsKeyboardDevice.cs +++ b/Windows/Perspex.Win32/Input/WindowsKeyboardDevice.cs @@ -54,7 +54,7 @@ namespace Perspex.Win32.Input public void WindowActivated(Window window) { - this.SetFocusedElement(window, false); + this.SetFocusedElement(window, NavigationMethod.Unspecified); } public string StringFromVirtualKey(uint virtualKey)