Focus Traversal Api by emmauss · Pull Request #18647 · AvaloniaUI/Avalonia (original) (raw)
What does the pull request do?
This PR is based on #18373 , and if moved out of draft, will supercede it.
This PR aims to address concern reported in #7607 . It implements a few of the core focus search api, and attempts to keep the core implementation as close to WinUI's as possible.
The following api are provided over the preceding PR;
namespace Avalonia.Input;
// FindNextElementOptions.cs public sealed class FindNextElementOptions { public InputElement? SearchRoot { get; init; } public Rect ExclusionRect { get; init; } public Rect? FocusHintRectangle { get; init; } public XYFocusNavigationStrategy? NavigationStrategyOverride { get; init; } public bool IgnoreOcclusivity { get; init; } }
// FocusManager.cs public FocusManager(IInputElement? contentRoot = null);
public bool TryMoveFocus(NavigationDirection direction)
public bool TryMoveFocus(NavigationDirection direction, FindNextElementOptions options)
public IInputElement? FindFirstFocusableElement()
public IInputElement? FindLastFocusableElement()
public static IInputElement? FindFirstFocusableElement(IInputElement searchScope)
public static IInputElement? FindLastFocusableElement(IInputElement searchScope)
public IInputElement? FindNextElement(NavigationDirection focusNavigationDirection)
public IInputElement? FindNextElement(NavigationDirection direction, FindNextElementOptions options)
public bool TryMoveFocus(NavigationDirection direction)
public bool TryMoveFocus(NavigationDirection direction, FindNextElementOptions options)
// InputElement.cs
protected internal virtual InputElement? GetNextTabStopOverride() => null;
protected internal virtual InputElement? GetPreviousTabStopOverride() => null;
protected internal virtual InputElement? GetFirstFocusableElementOverride() => null;
protected internal virtual InputElement? GetLastFocusableElementOverride() => null;
Implementation is as close to WinUI's as possible, with some differences. All api returns a IInputElement instead of AvaloniaObject, the counterpart to WinUI's DependencyObject. WinUI can have focusable DependencyObject without making them UIElements. We can't do this directly in Avalonia, as the special class WinUI made an exception for aren't AvaloniaObjects on our end. This are TextRuns, specifically Hyperlinks. All our TextRuns are plain CLR classes.
What is the current behavior?
What is the updated/expected behavior with this PR?
How was the solution implemented (if it's not obvious)?
Checklist
- Added unit tests (if possible)?
- Added XML documentation to any related classes?
- Consider submitting a PR to https://github.com/AvaloniaUI/avalonia-docs with user documentation
Breaking changes
Because focus search requires a root visual in all cases, FocusManager is no longer stored as a singleton in AvaloniaLocator, but instead each toplevel has its own FocusManager.