From a5a6f094cf48801bf5c437bd8e7b2ec05c2f097f Mon Sep 17 00:00:00 2001 From: Steven Kirk Date: Thu, 4 Dec 2014 17:45:44 +0100 Subject: [PATCH] Added keyboard navigation for ListBox. Need to override it for TreeView. --- .../Generators/ItemContainerGenerator.cs | 2 +- .../Primitives/SelectingItemsControl.cs | 78 +++++++++++++++++++ Perspex.Input/FocusNavigationDirection.cs | 54 +++++++++++++ Perspex.Input/InputElement.cs | 4 +- Perspex.Input/Perspex.Input.csproj | 1 + 5 files changed, 136 insertions(+), 3 deletions(-) create mode 100644 Perspex.Input/FocusNavigationDirection.cs diff --git a/Perspex.Controls/Generators/ItemContainerGenerator.cs b/Perspex.Controls/Generators/ItemContainerGenerator.cs index 91b0153493..45551874a2 100644 --- a/Perspex.Controls/Generators/ItemContainerGenerator.cs +++ b/Perspex.Controls/Generators/ItemContainerGenerator.cs @@ -33,7 +33,7 @@ namespace Perspex.Controls.Generators return this.state; } - set + private set { if (this.state != value) { diff --git a/Perspex.Controls/Primitives/SelectingItemsControl.cs b/Perspex.Controls/Primitives/SelectingItemsControl.cs index e53b993bcf..c5f4bc121f 100644 --- a/Perspex.Controls/Primitives/SelectingItemsControl.cs +++ b/Perspex.Controls/Primitives/SelectingItemsControl.cs @@ -7,6 +7,7 @@ namespace Perspex.Controls.Primitives { using System; + using System.Collections; using System.Linq; using Perspex.Controls.Presenters; using Perspex.Input; @@ -19,6 +20,8 @@ namespace Perspex.Controls.Primitives static SelectingItemsControl() { + FocusableProperty.OverrideDefaultValue(typeof(SelectingItemsControl), true); + SelectedItemProperty.Changed.Subscribe(x => { var control = x.Sender as SelectingItemsControl; @@ -36,6 +39,81 @@ namespace Perspex.Controls.Primitives set { this.SetValue(SelectedItemProperty, value); } } + protected static int GetIndexOfItem(IEnumerable items, object item) + { + if (items != null) + { + int index = 0; + + foreach (var i in items) + { + if (object.ReferenceEquals(i, item)) + { + return index; + } + + ++index; + } + } + + return -1; + } + + protected int GetIndexOfItem(object item) + { + return GetIndexOfItem(this.Items, item); + } + + protected virtual void MoveSelection(FocusNavigationDirection direction) + { + if (this.SelectedItem != null) + { + int offset = 0; + + switch (direction) + { + case FocusNavigationDirection.Up: + offset = -1; + break; + case FocusNavigationDirection.Down: + offset = 1; + break; + } + + if (offset != 0) + { + var currentIndex = GetIndexOfItem(this.SelectedItem); + var index = currentIndex + offset; + + if (index >= 0 && index < this.Items.Cast().Count()) + { + this.SelectedItem = this.Items.Cast().ElementAt(index); + } + } + } + } + + protected override void OnKeyDown(KeyEventArgs e) + { + switch (e.Key) + { + case Key.Up: + this.MoveSelection(FocusNavigationDirection.Up); + break; + case Key.Down: + this.MoveSelection(FocusNavigationDirection.Down); + break; + case Key.Left: + this.MoveSelection(FocusNavigationDirection.Left); + break; + case Key.Right: + this.MoveSelection(FocusNavigationDirection.Right); + break; + } + + e.Handled = true; + } + protected override void OnPointerPressed(PointerEventArgs e) { IVisual source = (IVisual)e.Source; diff --git a/Perspex.Input/FocusNavigationDirection.cs b/Perspex.Input/FocusNavigationDirection.cs new file mode 100644 index 0000000000..307f11cabd --- /dev/null +++ b/Perspex.Input/FocusNavigationDirection.cs @@ -0,0 +1,54 @@ +// ----------------------------------------------------------------------- +// +// Copyright 2014 MIT Licence. See licence.md for more information. +// +// ----------------------------------------------------------------------- + +namespace Perspex.Input +{ + /// + /// Describes how focus should be moved. + /// + public enum FocusNavigationDirection + { + /// + /// Move the focus to the next control in the tab order. + /// + Next, + + /// + /// Move the focus to the previous control in the tab order. + /// + Previous, + + /// + /// Move the focus to the first control in the tab order. + /// + First, + + /// + /// Move the focus to the last control in the tab order. + /// + Last, + + /// + /// Move the focus to the left. + /// + Left, + + /// + /// Move the focus to the right. + /// + Right, + + /// + /// Move the focus up. + /// + Up, + + /// + /// Move the focus down. + /// + Down, + } +} diff --git a/Perspex.Input/InputElement.cs b/Perspex.Input/InputElement.cs index 4c0038aae4..9d9978d8ea 100644 --- a/Perspex.Input/InputElement.cs +++ b/Perspex.Input/InputElement.cs @@ -135,12 +135,12 @@ namespace Perspex.Input public void Focus() { - Locator.Current.GetService().Focus(this); + FocusManager.Instance.Focus(this); } protected virtual void OnGotFocus(RoutedEventArgs e) { - this.IsFocused = true; + this.IsFocused = e.OriginalSource == this; } protected virtual void OnLostFocus(RoutedEventArgs e) diff --git a/Perspex.Input/Perspex.Input.csproj b/Perspex.Input/Perspex.Input.csproj index 6a9e6c18ca..ef7d2078b6 100644 --- a/Perspex.Input/Perspex.Input.csproj +++ b/Perspex.Input/Perspex.Input.csproj @@ -54,6 +54,7 @@ +