Browse Source

Removed directional navigation code.

repro-ienumerable-menu-navigation
Steven Kirk 8 years ago
parent
commit
2584f4bb18
  1. 5
      src/Avalonia.Controls/MenuItem.cs
  2. 9
      src/Avalonia.Controls/Presenters/ItemsPresenter.cs
  3. 5
      src/Avalonia.Controls/TreeViewItem.cs
  4. 33
      src/Avalonia.Input/KeyboardNavigation.cs
  5. 47
      src/Avalonia.Input/KeyboardNavigationHandler.cs
  6. 242
      src/Avalonia.Input/Navigation/DirectionalNavigation.cs
  7. 799
      tests/Avalonia.Input.UnitTests/KeyboardNavigationTests_Arrows.cs
  8. 31
      tests/Avalonia.Input.UnitTests/KeyboardNavigationTests_Custom.cs

5
src/Avalonia.Controls/MenuItem.cs

@ -72,10 +72,7 @@ namespace Avalonia.Controls
/// The default value for the <see cref="ItemsControl.ItemsPanel"/> property.
/// </summary>
private static readonly ITemplate<IPanel> DefaultPanel =
new FuncTemplate<IPanel>(() => new StackPanel
{
[KeyboardNavigation.DirectionalNavigationProperty] = KeyboardNavigationMode.Cycle,
});
new FuncTemplate<IPanel>(() => new StackPanel());
/// <summary>
/// The timer used to display submenus.

9
src/Avalonia.Controls/Presenters/ItemsPresenter.cs

@ -143,13 +143,6 @@ namespace Avalonia.Controls.Presenters
Virtualizer = ItemVirtualizer.Create(this);
((ILogicalScrollable)this).InvalidateScroll?.Invoke();
if (!Panel.IsSet(KeyboardNavigation.DirectionalNavigationProperty))
{
KeyboardNavigation.SetDirectionalNavigation(
(InputElement)Panel,
KeyboardNavigationMode.Contained);
}
KeyboardNavigation.SetTabNavigation(
(InputElement)Panel,
KeyboardNavigation.GetTabNavigation(this));
@ -175,4 +168,4 @@ namespace Avalonia.Controls.Presenters
((ILogicalScrollable)this).InvalidateScroll?.Invoke();
}
}
}
}

5
src/Avalonia.Controls/TreeViewItem.cs

@ -32,10 +32,7 @@ namespace Avalonia.Controls
ListBoxItem.IsSelectedProperty.AddOwner<TreeViewItem>();
private static readonly ITemplate<IPanel> DefaultPanel =
new FuncTemplate<IPanel>(() => new StackPanel
{
[KeyboardNavigation.DirectionalNavigationProperty] = KeyboardNavigationMode.Continue,
});
new FuncTemplate<IPanel>(() => new StackPanel());
private TreeView _treeView;
private bool _isExpanded;

33
src/Avalonia.Input/KeyboardNavigation.cs

@ -8,19 +8,6 @@ namespace Avalonia.Input
/// </summary>
public static class KeyboardNavigation
{
/// <summary>
/// Defines the DirectionalNavigation attached property.
/// </summary>
/// <remarks>
/// The DirectionalNavigation attached property defines how pressing arrow keys causes
/// focus to be navigated between the children of the container.
/// </remarks>
public static readonly AttachedProperty<KeyboardNavigationMode> DirectionalNavigationProperty =
AvaloniaProperty.RegisterAttached<InputElement, KeyboardNavigationMode>(
"DirectionalNavigation",
typeof(KeyboardNavigation),
KeyboardNavigationMode.None);
/// <summary>
/// Defines the TabNavigation attached property.
/// </summary>
@ -46,26 +33,6 @@ namespace Avalonia.Input
"TabOnceActiveElement",
typeof(KeyboardNavigation));
/// <summary>
/// Gets the <see cref="DirectionalNavigationProperty"/> for a container.
/// </summary>
/// <param name="element">The container.</param>
/// <returns>The <see cref="KeyboardNavigationMode"/> for the container.</returns>
public static KeyboardNavigationMode GetDirectionalNavigation(InputElement element)
{
return element.GetValue(DirectionalNavigationProperty);
}
/// <summary>
/// Sets the <see cref="DirectionalNavigationProperty"/> for a container.
/// </summary>
/// <param name="element">The container.</param>
/// <param name="value">The <see cref="KeyboardNavigationMode"/> for the container.</param>
public static void SetDirectionalNavigation(InputElement element, KeyboardNavigationMode value)
{
element.SetValue(DirectionalNavigationProperty, value);
}
/// <summary>
/// Gets the <see cref="TabNavigationProperty"/> for a container.
/// </summary>

47
src/Avalonia.Input/KeyboardNavigationHandler.cs

@ -85,7 +85,7 @@ namespace Avalonia.Input
}
else
{
return DirectionalNavigation.GetNext(element, direction);
throw new NotSupportedException();
}
}
@ -122,47 +122,12 @@ namespace Avalonia.Input
{
var current = FocusManager.Instance.Current;
if (current != null)
if (current != null && e.Key == Key.Tab)
{
NavigationDirection? direction = null;
switch (e.Key)
{
case Key.Tab:
direction = (e.Modifiers & InputModifiers.Shift) == 0 ?
NavigationDirection.Next : NavigationDirection.Previous;
break;
case Key.Up:
direction = NavigationDirection.Up;
break;
case Key.Down:
direction = NavigationDirection.Down;
break;
case Key.Left:
direction = NavigationDirection.Left;
break;
case Key.Right:
direction = NavigationDirection.Right;
break;
case Key.PageUp:
direction = NavigationDirection.PageUp;
break;
case Key.PageDown:
direction = NavigationDirection.PageDown;
break;
case Key.Home:
direction = NavigationDirection.First;
break;
case Key.End:
direction = NavigationDirection.Last;
break;
}
if (direction.HasValue)
{
Move(current, direction.Value, e.Modifiers);
e.Handled = true;
}
var direction = (e.Modifiers & InputModifiers.Shift) == 0 ?
NavigationDirection.Next : NavigationDirection.Previous;
Move(current, direction, e.Modifiers);
e.Handled = true;
}
}
}

242
src/Avalonia.Input/Navigation/DirectionalNavigation.cs

@ -1,242 +0,0 @@
// Copyright (c) The Avalonia Project. All rights reserved.
// Licensed under the MIT license. See licence.md file in the project root for full license information.
using System;
using System.Collections.Generic;
using System.Linq;
using Avalonia.VisualTree;
namespace Avalonia.Input.Navigation
{
/// <summary>
/// The implementation for default directional navigation.
/// </summary>
public static class DirectionalNavigation
{
/// <summary>
/// Gets the next control in the specified navigation direction.
/// </summary>
/// <param name="element">The element.</param>
/// <param name="direction">The navigation direction.</param>
/// <returns>
/// The next element in the specified direction, or null if <paramref name="element"/>
/// was the last in the requested direction.
/// </returns>
public static IInputElement GetNext(
IInputElement element,
NavigationDirection direction)
{
Contract.Requires<ArgumentNullException>(element != null);
Contract.Requires<ArgumentException>(
direction != NavigationDirection.Next &&
direction != NavigationDirection.Previous);
var container = element.GetVisualParent<IInputElement>();
if (container != null)
{
var mode = KeyboardNavigation.GetDirectionalNavigation((InputElement)container);
switch (mode)
{
case KeyboardNavigationMode.Continue:
return GetNextInContainer(element, container, direction) ??
GetFirstInNextContainer(element, element, direction);
case KeyboardNavigationMode.Cycle:
return GetNextInContainer(element, container, direction) ??
GetFocusableDescendant(container, direction);
case KeyboardNavigationMode.Contained:
return GetNextInContainer(element, container, direction);
default:
return null;
}
}
else
{
return GetFocusableDescendants(element).FirstOrDefault();
}
}
/// <summary>
/// Returns a value indicting whether the specified direction is forward.
/// </summary>
/// <param name="direction">The direction.</param>
/// <returns>True if the direction is forward.</returns>
private static bool IsForward(NavigationDirection direction)
{
return direction == NavigationDirection.Next ||
direction == NavigationDirection.Last ||
direction == NavigationDirection.Right ||
direction == NavigationDirection.Down;
}
/// <summary>
/// Gets the first or last focusable descendant of the specified element.
/// </summary>
/// <param name="container">The element.</param>
/// <param name="direction">The direction to search.</param>
/// <returns>The element or null if not found.##</returns>
private static IInputElement GetFocusableDescendant(IInputElement container, NavigationDirection direction)
{
return IsForward(direction) ?
GetFocusableDescendants(container).FirstOrDefault() :
GetFocusableDescendants(container).LastOrDefault();
}
/// <summary>
/// Gets the focusable descendants of the specified element.
/// </summary>
/// <param name="element">The element.</param>
/// <returns>The element's focusable descendants.</returns>
private static IEnumerable<IInputElement> GetFocusableDescendants(IInputElement element)
{
var children = element.GetVisualChildren().OfType<IInputElement>();
foreach (var child in children)
{
if (child.CanFocus())
{
yield return child;
}
if (child.CanFocusDescendants())
{
foreach (var descendant in GetFocusableDescendants(child))
{
yield return descendant;
}
}
}
}
/// <summary>
/// Gets the next item that should be focused in the specified container.
/// </summary>
/// <param name="element">The starting element/</param>
/// <param name="container">The container.</param>
/// <param name="direction">The direction.</param>
/// <returns>The next element, or null if the element is the last.</returns>
private static IInputElement GetNextInContainer(
IInputElement element,
IInputElement container,
NavigationDirection direction)
{
if (direction == NavigationDirection.Down)
{
var descendant = GetFocusableDescendants(element).FirstOrDefault();
if (descendant != null)
{
return descendant;
}
}
if (container != null)
{
var navigable = container as INavigableContainer;
if (navigable != null)
{
while (element != null)
{
element = navigable.GetControl(direction, element);
if (element != null && element.CanFocus())
{
break;
}
}
}
else
{
// TODO: Do a spatial search here if the container doesn't implement
// INavigableContainer.
element = null;
}
if (element != null && direction == NavigationDirection.Up)
{
var descendant = GetFocusableDescendants(element).LastOrDefault();
if (descendant != null)
{
return descendant;
}
}
return element;
}
return null;
}
/// <summary>
/// Gets the first item that should be focused in the next container.
/// </summary>
/// <param name="element">The element being navigated away from.</param>
/// <param name="container">The container.</param>
/// <param name="direction">The direction of the search.</param>
/// <returns>The first element, or null if there are no more elements.</returns>
private static IInputElement GetFirstInNextContainer(
IInputElement element,
IInputElement container,
NavigationDirection direction)
{
var parent = container.GetVisualParent<IInputElement>();
var isForward = IsForward(direction);
IInputElement next = null;
if (parent != null)
{
if (!isForward && parent.CanFocus())
{
return parent;
}
var siblings = parent.GetVisualChildren()
.OfType<IInputElement>()
.Where(FocusExtensions.CanFocusDescendants);
var sibling = isForward ?
siblings.SkipWhile(x => x != container).Skip(1).FirstOrDefault() :
siblings.TakeWhile(x => x != container).LastOrDefault();
if (sibling != null)
{
if (sibling is ICustomKeyboardNavigation custom)
{
var (handled, customNext) = custom.GetNext(element, direction);
if (handled)
{
return customNext;
}
}
if (sibling.CanFocus())
{
next = sibling;
}
else
{
next = isForward ?
GetFocusableDescendants(sibling).FirstOrDefault() :
GetFocusableDescendants(sibling).LastOrDefault();
}
}
if (next == null)
{
next = GetFirstInNextContainer(element, parent, direction);
}
}
else
{
next = isForward ?
GetFocusableDescendants(container).FirstOrDefault() :
GetFocusableDescendants(container).LastOrDefault();
}
return next;
}
}
}

799
tests/Avalonia.Input.UnitTests/KeyboardNavigationTests_Arrows.cs

@ -1,799 +0,0 @@
// Copyright (c) The Avalonia Project. All rights reserved.
// Licensed under the MIT license. See licence.md file in the project root for full license information.
using Avalonia.Controls;
using Xunit;
namespace Avalonia.Input.UnitTests
{
public class KeyboardNavigationTests_Arrows
{
[Fact]
public void Down_Continue_Returns_Down_Control_In_Container()
{
Button current;
Button next;
var top = new StackPanel
{
Children =
{
new StackPanel
{
[KeyboardNavigation.DirectionalNavigationProperty] = KeyboardNavigationMode.Continue,
Children =
{
new Button { Name = "Button1" },
(current = new Button { Name = "Button2" }),
(next = new Button { Name = "Button3" }),
}
},
new StackPanel
{
[KeyboardNavigation.DirectionalNavigationProperty] = KeyboardNavigationMode.Continue,
Children =
{
new Button { Name = "Button4" },
new Button { Name = "Button5" },
new Button { Name = "Button6" },
}
},
}
};
var result = KeyboardNavigationHandler.GetNext(current, NavigationDirection.Down);
Assert.Equal(next, result);
}
[Fact]
public void Down_Continue_Returns_First_Control_In_Down_Sibling_Container()
{
Button current;
Button next;
var top = new StackPanel
{
Children =
{
new StackPanel
{
[KeyboardNavigation.DirectionalNavigationProperty] = KeyboardNavigationMode.Continue,
Children =
{
new Button { Name = "Button1" },
new Button { Name = "Button2" },
(current = new Button { Name = "Button3" }),
}
},
new StackPanel
{
[KeyboardNavigation.DirectionalNavigationProperty] = KeyboardNavigationMode.Continue,
Children =
{
(next = new Button { Name = "Button4" }),
new Button { Name = "Button5" },
new Button { Name = "Button6" },
}
},
}
};
var result = KeyboardNavigationHandler.GetNext(current, NavigationDirection.Down);
Assert.Equal(next, result);
}
[Fact]
public void Down_Continue_Returns_Down_Sibling()
{
Button current;
Button next;
var top = new StackPanel
{
Children =
{
new StackPanel
{
[KeyboardNavigation.DirectionalNavigationProperty] = KeyboardNavigationMode.Continue,
Children =
{
new Button { Name = "Button1" },
new Button { Name = "Button2" },
(current = new Button { Name = "Button3" }),
}
},
(next = new Button { Name = "Button4" }),
}
};
var result = KeyboardNavigationHandler.GetNext(current, NavigationDirection.Down);
Assert.Equal(next, result);
}
[Fact]
public void Down_Continue_Returns_First_Control_In_Down_Uncle_Container()
{
Button current;
Button next;
var top = new StackPanel
{
Children =
{
new StackPanel
{
Children =
{
new StackPanel
{
[KeyboardNavigation.DirectionalNavigationProperty] = KeyboardNavigationMode.Continue,
Children =
{
new Button { Name = "Button1" },
new Button { Name = "Button2" },
(current = new Button { Name = "Button3" }),
}
},
},
},
new StackPanel
{
[KeyboardNavigation.DirectionalNavigationProperty] = KeyboardNavigationMode.Continue,
Children =
{
(next = new Button { Name = "Button4" }),
new Button { Name = "Button5" },
new Button { Name = "Button6" },
}
},
}
};
var result = KeyboardNavigationHandler.GetNext(current, NavigationDirection.Down);
Assert.Equal(next, result);
}
[Fact]
public void Down_Continue_Returns_Child_Of_Top_Level()
{
Button next;
var top = new StackPanel
{
[KeyboardNavigation.DirectionalNavigationProperty] = KeyboardNavigationMode.Continue,
Children =
{
(next = new Button { Name = "Button1" }),
}
};
var result = KeyboardNavigationHandler.GetNext(top, NavigationDirection.Down);
Assert.Equal(next, result);
}
[Fact]
public void Down_Continue_Wraps()
{
Button current;
Button next;
var top = new StackPanel
{
[KeyboardNavigation.DirectionalNavigationProperty] = KeyboardNavigationMode.Continue,
Children =
{
new StackPanel
{
[KeyboardNavigation.DirectionalNavigationProperty] = KeyboardNavigationMode.Continue,
Children =
{
new StackPanel
{
[KeyboardNavigation.DirectionalNavigationProperty] = KeyboardNavigationMode.Continue,
Children =
{
(next = new Button { Name = "Button1" }),
new Button { Name = "Button2" },
new Button { Name = "Button3" },
}
},
},
},
new StackPanel
{
[KeyboardNavigation.DirectionalNavigationProperty] = KeyboardNavigationMode.Continue,
Children =
{
new Button { Name = "Button4" },
new Button { Name = "Button5" },
(current = new Button { Name = "Button6" }),
}
},
}
};
var result = KeyboardNavigationHandler.GetNext(current, NavigationDirection.Down);
Assert.Equal(next, result);
}
[Fact]
public void Down_Cycle_Returns_Down_Control_In_Container()
{
Button current;
Button next;
var top = new StackPanel
{
Children =
{
new StackPanel
{
[KeyboardNavigation.DirectionalNavigationProperty] = KeyboardNavigationMode.Cycle,
Children =
{
new Button { Name = "Button1" },
(current = new Button { Name = "Button2" }),
(next = new Button { Name = "Button3" }),
}
},
new StackPanel
{
Children =
{
new Button { Name = "Button4" },
new Button { Name = "Button5" },
new Button { Name = "Button6" },
}
},
}
};
var result = KeyboardNavigationHandler.GetNext(current, NavigationDirection.Down);
Assert.Equal(next, result);
}
[Fact]
public void Down_Cycle_Wraps_To_First()
{
Button current;
Button next;
var top = new StackPanel
{
Children =
{
new StackPanel
{
[KeyboardNavigation.DirectionalNavigationProperty] = KeyboardNavigationMode.Cycle,
Children =
{
(next = new Button { Name = "Button1" }),
new Button { Name = "Button2" },
(current = new Button { Name = "Button3" }),
}
},
new StackPanel
{
Children =
{
new Button { Name = "Button4" },
new Button { Name = "Button5" },
new Button { Name = "Button6" },
}
},
}
};
var result = KeyboardNavigationHandler.GetNext(current, NavigationDirection.Down);
Assert.Equal(next, result);
}
[Fact]
public void Down_Contained_Returns_Down_Control_In_Container()
{
Button current;
Button next;
var top = new StackPanel
{
Children =
{
new StackPanel
{
[KeyboardNavigation.DirectionalNavigationProperty] = KeyboardNavigationMode.Contained,
Children =
{
new Button { Name = "Button1" },
(current = new Button { Name = "Button2" }),
(next = new Button { Name = "Button3" }),
}
},
new StackPanel
{
[KeyboardNavigation.DirectionalNavigationProperty] = KeyboardNavigationMode.Contained,
Children =
{
new Button { Name = "Button4" },
new Button { Name = "Button5" },
new Button { Name = "Button6" },
}
},
}
};
var result = KeyboardNavigationHandler.GetNext(current, NavigationDirection.Down);
Assert.Equal(next, result);
}
[Fact]
public void Down_Contained_Stops_At_End()
{
Button current;
var top = new StackPanel
{
Children =
{
new StackPanel
{
[KeyboardNavigation.DirectionalNavigationProperty] = KeyboardNavigationMode.Contained,
Children =
{
new Button { Name = "Button1" },
new Button { Name = "Button2" },
(current = new Button { Name = "Button3" }),
}
},
new StackPanel
{
[KeyboardNavigation.DirectionalNavigationProperty] = KeyboardNavigationMode.Contained,
Children =
{
new Button { Name = "Button4" },
new Button { Name = "Button5" },
new Button { Name = "Button6" },
}
},
}
};
var result = KeyboardNavigationHandler.GetNext(current, NavigationDirection.Down);
Assert.Null(result);
}
[Fact]
public void Down_None_Does_Nothing()
{
Button current;
var top = new StackPanel
{
Children =
{
new StackPanel
{
[KeyboardNavigation.DirectionalNavigationProperty] = KeyboardNavigationMode.None,
Children =
{
new Button { Name = "Button1" },
(current = new Button { Name = "Button2" }),
new Button { Name = "Button3" },
}
},
new StackPanel
{
[KeyboardNavigation.DirectionalNavigationProperty] = KeyboardNavigationMode.Contained,
Children =
{
new Button { Name = "Button4" },
new Button { Name = "Button5" },
new Button { Name = "Button6" },
}
},
}
};
var result = KeyboardNavigationHandler.GetNext(current, NavigationDirection.Down);
Assert.Null(result);
}
[Fact]
public void Up_Continue_Returns_Up_Control_In_Container()
{
Button current;
Button next;
var top = new StackPanel
{
Children =
{
new StackPanel
{
[KeyboardNavigation.DirectionalNavigationProperty] = KeyboardNavigationMode.Continue,
Children =
{
new Button { Name = "Button1" },
(next = new Button { Name = "Button2" }),
(current = new Button { Name = "Button3" }),
}
},
new StackPanel
{
[KeyboardNavigation.DirectionalNavigationProperty] = KeyboardNavigationMode.Contained,
Children =
{
new Button { Name = "Button4" },
new Button { Name = "Button5" },
new Button { Name = "Button6" },
}
},
}
};
var result = KeyboardNavigationHandler.GetNext(current, NavigationDirection.Up);
Assert.Equal(next, result);
}
[Fact]
public void Up_Continue_Returns_Last_Control_In_Up_Sibling_Container()
{
Button current;
Button next;
var top = new StackPanel
{
Children =
{
new StackPanel
{
[KeyboardNavigation.DirectionalNavigationProperty] = KeyboardNavigationMode.Continue,
Children =
{
new Button { Name = "Button1" },
new Button { Name = "Button2" },
(next = new Button { Name = "Button3" }),
}
},
new StackPanel
{
[KeyboardNavigation.DirectionalNavigationProperty] = KeyboardNavigationMode.Continue,
Children =
{
(current = new Button { Name = "Button4" }),
new Button { Name = "Button5" },
new Button { Name = "Button6" },
}
},
}
};
var result = KeyboardNavigationHandler.GetNext(current, NavigationDirection.Up);
Assert.Equal(next, result);
}
[Fact]
public void Up_Continue_Returns_Last_Child_Of_Sibling()
{
Button current;
Button next;
var top = new StackPanel
{
[KeyboardNavigation.DirectionalNavigationProperty] = KeyboardNavigationMode.Continue,
Children =
{
new StackPanel
{
[KeyboardNavigation.DirectionalNavigationProperty] = KeyboardNavigationMode.Continue,
Children =
{
new Button { Name = "Button1" },
new Button { Name = "Button2" },
(next = new Button { Name = "Button3" }),
}
},
(current = new Button { Name = "Button4" }),
}
};
var result = KeyboardNavigationHandler.GetNext(current, NavigationDirection.Up);
Assert.Equal(next, result);
}
[Fact]
public void Up_Continue_Returns_Last_Control_In_Up_Nephew_Container()
{
Button current;
Button next;
var top = new StackPanel
{
Children =
{
new StackPanel
{
Children =
{
new StackPanel
{
[KeyboardNavigation.DirectionalNavigationProperty] = KeyboardNavigationMode.Continue,
Children =
{
new Button { Name = "Button1" },
new Button { Name = "Button2" },
(next = new Button { Name = "Button3" }),
}
},
},
},
new StackPanel
{
[KeyboardNavigation.DirectionalNavigationProperty] = KeyboardNavigationMode.Continue,
Children =
{
(current = new Button { Name = "Button4" }),
new Button { Name = "Button5" },
new Button { Name = "Button6" },
}
},
}
};
var result = KeyboardNavigationHandler.GetNext(current, NavigationDirection.Up);
Assert.Equal(next, result);
}
[Fact]
public void Up_Continue_Wraps()
{
Button current;
Button next;
var top = new StackPanel
{
Children =
{
new StackPanel
{
Children =
{
new StackPanel
{
[KeyboardNavigation.DirectionalNavigationProperty] = KeyboardNavigationMode.Continue,
Children =
{
(current = new Button { Name = "Button1" }),
new Button { Name = "Button2" },
new Button { Name = "Button3" },
}
},
},
},
new StackPanel
{
[KeyboardNavigation.DirectionalNavigationProperty] = KeyboardNavigationMode.Continue,
Children =
{
new Button { Name = "Button4" },
new Button { Name = "Button5" },
(next = new Button { Name = "Button6" }),
}
},
}
};
var result = KeyboardNavigationHandler.GetNext(current, NavigationDirection.Up);
Assert.Equal(next, result);
}
[Fact]
public void Up_Continue_Returns_Parent()
{
Button current;
var top = new Decorator
{
Focusable = true,
[KeyboardNavigation.DirectionalNavigationProperty] = KeyboardNavigationMode.Continue,
Child = current = new Button
{
Name = "Button",
}
};
var result = KeyboardNavigationHandler.GetNext(current, NavigationDirection.Up);
Assert.Equal(top, result);
}
[Fact]
public void Up_Cycle_Returns_Up_Control_In_Container()
{
Button current;
Button next;
var top = new StackPanel
{
Children =
{
new StackPanel
{
[KeyboardNavigation.DirectionalNavigationProperty] = KeyboardNavigationMode.Cycle,
Children =
{
(next = new Button { Name = "Button1" }),
(current = new Button { Name = "Button2" }),
new Button { Name = "Button3" },
}
},
new StackPanel
{
[KeyboardNavigation.DirectionalNavigationProperty] = KeyboardNavigationMode.Cycle,
Children =
{
new Button { Name = "Button4" },
new Button { Name = "Button5" },
new Button { Name = "Button6" },
}
},
}
};
var result = KeyboardNavigationHandler.GetNext(current, NavigationDirection.Up);
Assert.Equal(next, result);
}
[Fact]
public void Up_Cycle_Wraps_To_Last()
{
Button current;
Button next;
var top = new StackPanel
{
Children =
{
new StackPanel
{
[KeyboardNavigation.DirectionalNavigationProperty] = KeyboardNavigationMode.Cycle,
Children =
{
(current = new Button { Name = "Button1" }),
new Button { Name = "Button2" },
(next = new Button { Name = "Button3" }),
}
},
new StackPanel
{
[KeyboardNavigation.DirectionalNavigationProperty] = KeyboardNavigationMode.Cycle,
Children =
{
new Button { Name = "Button4" },
new Button { Name = "Button5" },
new Button { Name = "Button6" },
}
},
}
};
var result = KeyboardNavigationHandler.GetNext(current, NavigationDirection.Up);
Assert.Equal(next, result);
}
[Fact]
public void Up_Contained_Returns_Up_Control_In_Container()
{
Button current;
Button next;
var top = new StackPanel
{
Children =
{
new StackPanel
{
[KeyboardNavigation.DirectionalNavigationProperty] = KeyboardNavigationMode.Contained,
Children =
{
(next = new Button { Name = "Button1" }),
(current = new Button { Name = "Button2" }),
new Button { Name = "Button3" },
}
},
new StackPanel
{
[KeyboardNavigation.DirectionalNavigationProperty] = KeyboardNavigationMode.Contained,
Children =
{
new Button { Name = "Button4" },
new Button { Name = "Button5" },
new Button { Name = "Button6" },
}
},
}
};
var result = KeyboardNavigationHandler.GetNext(current, NavigationDirection.Up);
Assert.Equal(next, result);
}
[Fact]
public void Up_Contained_Stops_At_Beginning()
{
Button current;
var top = new StackPanel
{
Children =
{
new StackPanel
{
[KeyboardNavigation.DirectionalNavigationProperty] = KeyboardNavigationMode.Contained,
Children =
{
(current = new Button { Name = "Button1" }),
new Button { Name = "Button2" },
new Button { Name = "Button3" },
}
},
new StackPanel
{
[KeyboardNavigation.DirectionalNavigationProperty] = KeyboardNavigationMode.Contained,
Children =
{
new Button { Name = "Button4" },
new Button { Name = "Button5" },
new Button { Name = "Button6" },
}
},
}
};
var result = KeyboardNavigationHandler.GetNext(current, NavigationDirection.Up);
Assert.Null(result);
}
[Fact]
public void Up_Contained_Doesnt_Return_Child_Control()
{
Decorator current;
var top = new StackPanel
{
[KeyboardNavigation.DirectionalNavigationProperty] = KeyboardNavigationMode.Contained,
Children =
{
(current = new Decorator
{
Focusable = true,
Child = new Button(),
})
}
};
var result = KeyboardNavigationHandler.GetNext(current, NavigationDirection.Up);
Assert.Null(result);
}
}
}

31
tests/Avalonia.Input.UnitTests/KeyboardNavigationTests_Custom.cs

@ -140,37 +140,6 @@ namespace Avalonia.Input.UnitTests
Assert.Same(next, result);
}
[Fact]
public void Right_Should_Custom_Navigate_From_Outside()
{
Button current;
Button next;
var target = new CustomNavigatingStackPanel
{
Children =
{
new Button { Content = "Button 1" },
new Button { Content = "Button 2" },
(next = new Button { Content = "Button 3" }),
},
NextControl = next,
};
var root = new StackPanel
{
Children =
{
(current = new Button { Content = "Outside" }),
target,
},
[KeyboardNavigation.DirectionalNavigationProperty] = KeyboardNavigationMode.Continue,
};
var result = KeyboardNavigationHandler.GetNext(current, NavigationDirection.Right);
Assert.Same(next, result);
}
[Fact]
public void Tab_Should_Navigate_Outside_When_Null_Returned_As_Next()
{

Loading…
Cancel
Save