Browse Source

Pass navigation method in GotFocus event.

And only focus selectable items when focus comes from the pointer, or
directional keys.
pull/72/merge
Steven Kirk 11 years ago
parent
commit
d161428f52
  1. 2
      Perspex.Controls/Control.cs
  2. 14
      Perspex.Controls/Primitives/SelectingItemsControl.cs
  3. 20
      Perspex.Input/FocusManager.cs
  4. 8
      Perspex.Input/GotFocusEventArgs.cs
  5. 6
      Perspex.Input/IFocusManager.cs
  6. 2
      Perspex.Input/IKeyboardDevice.cs
  7. 2
      Perspex.Input/InputElement.cs
  8. 4
      Perspex.Input/KeyboardDevice.cs
  9. 5
      Perspex.Input/KeyboardNavigationHandler.cs
  10. 35
      Perspex.Input/NavigationMethod.cs
  11. 1
      Perspex.Input/Perspex.Input.csproj
  12. 1
      TestApplication/Program.cs
  13. 52
      Tests/Perspex.Controls.UnitTests/Primitives/SelectingItemsControlTests.cs
  14. 2
      Windows/Perspex.Win32/Input/WindowsKeyboardDevice.cs

2
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);

14
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);
}
}
/// <inheritdoc/>
protected override void OnPointerPressed(PointerPressEventArgs e)
{
base.OnPointerPressed(e);
e.Handled = true;
}
/// <summary>

20
Perspex.Input/FocusManager.cs

@ -65,10 +65,8 @@ namespace Perspex.Input
/// Focuses a control.
/// </summary>
/// <param name="control">The control to focus.</param>
/// <param name="keyboardNavigated">
/// Whether the control was focused by a keypress (e.g. the Tab key).
/// </param>
public void Focus(IInputElement control, bool keyboardNavigated = false)
/// <param name="method">The method by which focus was changed.</param>
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
/// </summary>
/// <param name="scope">The focus scope.</param>
/// <param name="element">The element to focus. May be null.</param>
/// <param name="keyboardNavigated">
/// Whether the control was focused by a keypress (e.g. the Tab key).
/// </param>
/// <param name="method">The method by which focus was changed.</param>
/// <remarks>
/// If the specified scope is the current <see cref="Scope"/> 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<ArgumentNullException>(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);
}
}
}

8
Perspex.Input/GotFocusEventArgs.cs

@ -8,12 +8,14 @@ namespace Perspex.Input
{
using Perspex.Interactivity;
/// <summary>
/// Holds arguments for a <see cref="InputElement.GotFocusEvent"/>.
/// </summary>
public class GotFocusEventArgs : RoutedEventArgs
{
/// <summary>
/// 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.
/// </summary>
public bool KeyboardNavigated { get; set; }
public NavigationMethod NavigationMethod { get; set; }
}
}

6
Perspex.Input/IFocusManager.cs

@ -22,10 +22,8 @@ namespace Perspex.Input
/// Focuses a control.
/// </summary>
/// <param name="control">The control to focus.</param>
/// <param name="keyboardNavigated">
/// Whether the control was focused by a keypress (e.g. the Tab key).
/// </param>
void Focus(IInputElement focusable, bool keyboardNavigated = false);
/// <param name="method">The method by which focus was changed.</param>
void Focus(IInputElement control, NavigationMethod method = NavigationMethod.Unspecified);
/// <summary>
/// Notifies the focus manager of a change in focus scope.

2
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);
}
}

2
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)

4
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,
});
}
}

5
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);
}
}

35
Perspex.Input/NavigationMethod.cs

@ -0,0 +1,35 @@
// -----------------------------------------------------------------------
// <copyright file="NavigationMethod.cs" company="Steven Kirk">
// Copyright 2015 MIT Licence. See licence.md for more information.
// </copyright>
// -----------------------------------------------------------------------
namespace Perspex.Input
{
/// <summary>
/// Defines the method by which a focus change occurred.
/// </summary>
public enum NavigationMethod
{
/// <summary>
/// The focus was changed by an unspecified method, e.g. calling
/// <see cref="InputElement.Focus"/>.
/// </summary>
Unspecified,
/// <summary>
/// The focus was changed by the user tabbing between control.
/// </summary>
Tab,
/// <summary>
/// The focus was changed by the user pressing a directional navigation key.
/// </summary>
Directional,
/// <summary>
/// The focus was changed by a pointer click.
/// </summary>
Pointer,
}
}

1
Perspex.Input/Perspex.Input.csproj

@ -61,6 +61,7 @@
<ItemGroup>
<Compile Include="GlobalSuppressions.cs" />
<Compile Include="AccessKeyHandler.cs" />
<Compile Include="NavigationMethod.cs" />
<Compile Include="IInputRoot.cs" />
<Compile Include="IMainMenu.cs" />
<Compile Include="IAccessKeyHandler.cs" />

1
TestApplication/Program.cs

@ -492,7 +492,6 @@ namespace TestApplication
(listBox = new ListBox
{
Items = listBoxData,
SelectedIndex = 0,
MaxHeight = 300,
}),
new DropDown

52
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()
{

2
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)

Loading…
Cancel
Save