Skip to content

[DRAFT] - Focus Traversal Api #18647

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 7 commits into
base: master
Choose a base branch
from
Draft

[DRAFT] - Focus Traversal Api #18647

wants to merge 7 commits into from

Conversation

emmauss
Copy link
Contributor

@emmauss emmauss commented Apr 14, 2025

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 class FindNextElementOptions
{
    public InputElement? SearchRoot { get; set; }
    public Rect ExclusionRect { get; set; }
    public Rect? FocusHintRectangle { get; set; }
    public XYFocusNavigationStrategy? NavigationStrategyOverride { get; set; }
    public bool IgnoreOcclusivity { get; set; }
}

// FocusManager.cs
public FocusManager(IInputElement? contentRoot = null);

public bool TryMoveFocus(NavigationDirection direction)

public bool TryMoveFocus(NavigationDirection direction, FindNextElementOptions findNextElementOptions)

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 focusNavigationDirection, FindNextElementOptions findNextElementOptions)

public bool TryMoveFocus(NavigationDirection direction)

public bool TryMoveFocus(NavigationDirection direction, FindNextElementOptions findNextElementOptions)

// 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

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.

Obsoletions / Deprecations

Fixed issues

@emmauss emmauss requested a review from grokys April 14, 2025 13:01
@robloo
Copy link
Contributor

robloo commented Apr 14, 2025

FYI @amwx. Since you made the previous attempt in #8392 you might want to take a look.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants