Browse Source

Skip disabled controls when moving to first/last item

pull/8514/head
Luis von der Eltz 4 years ago
parent
commit
d9ce64e1b0
  1. 29
      src/Avalonia.Controls/ItemsControl.cs
  2. 4
      src/Avalonia.Controls/Platform/DefaultMenuInteractionHandler.cs
  3. 24
      tests/Avalonia.Controls.UnitTests/Primitives/SelectingItemsControlTests.cs

29
src/Avalonia.Controls/ItemsControl.cs

@ -502,25 +502,34 @@ namespace Avalonia.Controls
IInputElement? from,
bool wrap)
{
IInputElement? result;
var c = from;
do
for(;;)
{
result = container.GetControl(direction, c, wrap);
var result = container.GetControl(direction, from, wrap);
if (result is null || result == from)
{
return null;
}
if (result != null &&
result.Focusable &&
if (result.Focusable &&
result.IsEffectivelyEnabled &&
result.IsEffectivelyVisible)
{
return result;
}
c = result;
} while (c != null && c != from && direction != NavigationDirection.First && direction != NavigationDirection.Last);
direction = direction switch
{
//We did not find an enabled first item. Move downwards until we find one.
NavigationDirection.First => NavigationDirection.Down,
//We did not find an enabled last item. Move upwards until we find one.
NavigationDirection.Last => NavigationDirection.Up,
_ => direction
};
return null;
from = result;
}
}
private void PresenterChildIndexChanged(object? sender, ChildIndexChangedEventArgs e)

4
src/Avalonia.Controls/Platform/DefaultMenuInteractionHandler.cs

@ -53,7 +53,7 @@ namespace Avalonia.Controls.Platform
Menu.PointerPressed += PointerPressed;
Menu.PointerReleased += PointerReleased;
Menu.AddHandler(AccessKeyHandler.AccessKeyPressedEvent, AccessKeyPressed);
Menu.AddHandler(Avalonia.Controls.Menu.MenuOpenedEvent, MenuOpened);
Menu.AddHandler(MenuBase.MenuOpenedEvent, MenuOpened);
Menu.AddHandler(MenuItem.PointerEnteredItemEvent, PointerEntered);
Menu.AddHandler(MenuItem.PointerExitedItemEvent, PointerExited);
Menu.AddHandler(InputElement.PointerMovedEvent, PointerMoved);
@ -89,7 +89,7 @@ namespace Avalonia.Controls.Platform
Menu.PointerPressed -= PointerPressed;
Menu.PointerReleased -= PointerReleased;
Menu.RemoveHandler(AccessKeyHandler.AccessKeyPressedEvent, AccessKeyPressed);
Menu.RemoveHandler(Avalonia.Controls.Menu.MenuOpenedEvent, MenuOpened);
Menu.RemoveHandler(MenuBase.MenuOpenedEvent, MenuOpened);
Menu.RemoveHandler(MenuItem.PointerEnteredItemEvent, PointerEntered);
Menu.RemoveHandler(MenuItem.PointerExitedItemEvent, PointerExited);
Menu.RemoveHandler(InputElement.PointerMovedEvent, PointerMoved);

24
tests/Avalonia.Controls.UnitTests/Primitives/SelectingItemsControlTests.cs

@ -1615,48 +1615,44 @@ namespace Avalonia.Controls.UnitTests.Primitives
target.MoveSelection(NavigationDirection.Next, true);
}
[Fact(Timeout = 2000)]
public async Task MoveSelection_Does_Not_Hang_With_No_Focusable_Controls_And_Moving_Selection_To_The_First_Item()
[Fact]
public void MoveSelection_Skips_Non_Focusable_Controls_When_Moving_To_Last_Item()
{
var target = new TestSelector
{
Template = Template(),
Items = new[]
{
new ListBoxItem { Focusable = false },
new ListBoxItem(),
new ListBoxItem { Focusable = false },
}
};
target.Measure(new Size(100, 100));
target.Arrange(new Rect(0, 0, 100, 100));
target.MoveSelection(NavigationDirection.Last, true);
// Timeout in xUnit doesen't work with synchronous methods so we need to apply hack below.
// https://github.com/xunit/xunit/issues/2222
await Task.Run(() => target.MoveSelection(NavigationDirection.First, true));
Assert.Equal(-1, target.SelectedIndex);
Assert.Equal(0, target.SelectedIndex);
}
[Fact(Timeout = 2000)]
public async Task MoveSelection_Does_Not_Hang_With_No_Focusable_Controls_And_Moving_Selection_To_The_Last_Item()
[Fact]
public void MoveSelection_Skips_Non_Focusable_Controls_When_Moving_To_First_Item()
{
var target = new TestSelector
{
Template = Template(),
Items = new[]
{
new ListBoxItem(),
new ListBoxItem { Focusable = false },
new ListBoxItem(),
}
};
target.Measure(new Size(100, 100));
target.Arrange(new Rect(0, 0, 100, 100));
target.MoveSelection(NavigationDirection.Last, true);
// Timeout in xUnit doesen't work with synchronous methods so we need to apply hack below.
// https://github.com/xunit/xunit/issues/2222
await Task.Run(() => target.MoveSelection(NavigationDirection.Last, true));
Assert.Equal(-1, target.SelectedIndex);
Assert.Equal(1, target.SelectedIndex);
}
[Fact]

Loading…
Cancel
Save