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>
protected override void OnKeyDown(KeyEventArgs e)
{
var focus = FocusManager.Instance;
var direction = e.Key.ToNavigationDirection();
var container = Presenter?.Panel as INavigableContainer;
if (container == null ||
focus.Current == null ||
direction == null ||
direction.Value.IsTab())
if (!e.Handled)
{
return;
}
var current = focus.Current
.GetSelfAndVisualAncestors()
.OfType<IInputElement>()
.FirstOrDefault(x => x.VisualParent == container);
var focus = FocusManager.Instance;
var direction = e.Key.ToNavigationDirection();
var container = Presenter?.Panel as INavigableContainer;
if (container == null ||
focus.Current == null ||
direction == null ||
direction.Value.IsTab())
{
return;
}
if (current != null)
{
var next = container.GetControl(direction.Value, current);
var current = focus.Current
.GetSelfAndVisualAncestors()
.OfType<IInputElement>()
.FirstOrDefault(x => x.VisualParent == container);
if (next != null)
if (current != null)
{
focus.Focus(next, NavigationMethod.Directional);
e.Handled = true;
var next = GetNextControl(container, direction.Value, current);
if (next != null)
{
focus.Focus(next, NavigationMethod.Directional);
e.Handled = true;
}
}
}
@ -498,5 +501,27 @@ namespace Avalonia.Controls
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 System.Collections.ObjectModel;
using Avalonia.UnitTests;
using Avalonia.Input;
namespace Avalonia.Controls.UnitTests
{
@ -494,6 +495,77 @@ namespace Avalonia.Controls.UnitTests
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
{
public Item(string value)

Loading…
Cancel
Save