Browse Source

Don't focus non-focusable controls.

When navigating `ItemsControl` with keyboard.
repro-ienumerable-menu-navigation
Steven Kirk 8 years ago
parent
commit
1e12b2c37b
  1. 67
      src/Avalonia.Controls/ItemsControl.cs
  2. 72
      tests/Avalonia.Controls.UnitTests/ItemsControlTests.cs

67
src/Avalonia.Controls/ItemsControl.cs

@ -330,31 +330,34 @@ namespace Avalonia.Controls
/// <param name="e">The key events.</param> /// <param name="e">The key events.</param>
protected override void OnKeyDown(KeyEventArgs e) protected override void OnKeyDown(KeyEventArgs e)
{ {
var focus = FocusManager.Instance; if (!e.Handled)
var direction = e.Key.ToNavigationDirection();
var container = Presenter?.Panel as INavigableContainer;
if (container == null ||
focus.Current == null ||
direction == null ||
direction.Value.IsTab())
{ {
return; var focus = FocusManager.Instance;
} var direction = e.Key.ToNavigationDirection();
var container = Presenter?.Panel as INavigableContainer;
var current = focus.Current
.GetSelfAndVisualAncestors() if (container == null ||
.OfType<IInputElement>() focus.Current == null ||
.FirstOrDefault(x => x.VisualParent == container); direction == null ||
direction.Value.IsTab())
{
return;
}
if (current != null) var current = focus.Current
{ .GetSelfAndVisualAncestors()
var next = container.GetControl(direction.Value, current); .OfType<IInputElement>()
.FirstOrDefault(x => x.VisualParent == container);
if (next != null) if (current != null)
{ {
focus.Focus(next, NavigationMethod.Directional); var next = GetNextControl(container, direction.Value, current);
e.Handled = true;
if (next != null)
{
focus.Focus(next, NavigationMethod.Directional);
e.Handled = true;
}
} }
} }
@ -498,5 +501,27 @@ namespace Avalonia.Controls
ItemCount = Items.Count(); ItemCount = Items.Count();
} }
} }
protected static IInputElement GetNextControl(
INavigableContainer container,
NavigationDirection direction,
IInputElement from)
{
IInputElement result;
while (from != null)
{
result = container.GetControl(direction, from);
if (result?.Focusable == true)
{
return result;
}
from = result;
}
return null;
}
} }
} }

72
tests/Avalonia.Controls.UnitTests/ItemsControlTests.cs

@ -11,6 +11,7 @@ using Avalonia.VisualTree;
using Xunit; using Xunit;
using System.Collections.ObjectModel; using System.Collections.ObjectModel;
using Avalonia.UnitTests; using Avalonia.UnitTests;
using Avalonia.Input;
namespace Avalonia.Controls.UnitTests namespace Avalonia.Controls.UnitTests
{ {
@ -494,6 +495,77 @@ namespace Avalonia.Controls.UnitTests
Assert.NotNull(NameScope.GetNameScope((TextBlock)container.Child)); Assert.NotNull(NameScope.GetNameScope((TextBlock)container.Child));
} }
[Fact]
public void Focuses_Next_Item_On_Key_Down()
{
using (UnitTestApplication.Start(TestServices.RealFocus))
{
var items = new object[]
{
new Button(),
new Button(),
};
var target = new ItemsControl
{
Template = GetTemplate(),
Items = items,
};
var root = new TestRoot { Child = target };
target.ApplyTemplate();
target.Presenter.ApplyTemplate();
target.Presenter.Panel.Children[0].Focus();
target.RaiseEvent(new KeyEventArgs
{
RoutedEvent = InputElement.KeyDownEvent,
Key = Key.Down,
});
Assert.Equal(
target.Presenter.Panel.Children[1],
FocusManager.Instance.Current);
}
}
[Fact]
public void Does_Not_Focus_Non_Focusable_Item_On_Key_Down()
{
using (UnitTestApplication.Start(TestServices.RealFocus))
{
var items = new object[]
{
new Button(),
new Button { Focusable = false },
new Button(),
};
var target = new ItemsControl
{
Template = GetTemplate(),
Items = items,
};
var root = new TestRoot { Child = target };
target.ApplyTemplate();
target.Presenter.ApplyTemplate();
target.Presenter.Panel.Children[0].Focus();
target.RaiseEvent(new KeyEventArgs
{
RoutedEvent = InputElement.KeyDownEvent,
Key = Key.Down,
});
Assert.Equal(
target.Presenter.Panel.Children[2],
FocusManager.Instance.Current);
}
}
private class Item private class Item
{ {
public Item(string value) public Item(string value)

Loading…
Cancel
Save