Skip to content

Commit

Permalink
fix: Move Page navigation focus to outer elements if available
Browse files Browse the repository at this point in the history
  • Loading branch information
MartinZikmund committed Jan 28, 2022
1 parent 36a7178 commit ee211c9
Show file tree
Hide file tree
Showing 6 changed files with 35 additions and 29 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -184,7 +184,6 @@ public async Task When_Page_Navigates_Focus_Without_Outer_Wrapper()
[TestMethod]
[RunsOnUIThread]
[RequiresFullWindow]
[Ignore("This test only passes on Windows - see #7900")]
public async Task When_Page_Navigates_Focus_With_Outer_Before()
{
var stackPanel = new StackPanel();
Expand Down Expand Up @@ -252,7 +251,6 @@ public async Task When_Page_Navigates_Focus_Outside_Frame()
[TestMethod]
[RunsOnUIThread]
[RequiresFullWindow]
[Ignore("This test only passes on Windows - see #7900")]
public async Task When_Page_Navigates_Focus_With_Outer_After()
{
var stackPanel = new StackPanel();
Expand Down Expand Up @@ -320,7 +318,6 @@ public async Task When_Page_Navigate_Back_Without_Outer_Wrapper()
[TestMethod]
[RunsOnUIThread]
[RequiresFullWindow]
[Ignore("This test only passes on Windows - see #7900")]
public async Task When_Page_Navigate_Back_With_Outer_Before()
{
var stackPanel = new StackPanel();
Expand Down Expand Up @@ -355,7 +352,6 @@ public async Task When_Page_Navigate_Back_With_Outer_Before()
[TestMethod]
[RunsOnUIThread]
[RequiresFullWindow]
[Ignore("This test only passes on Windows - see #7900")]
public async Task When_Page_Navigate_Back_With_Outer_After()
{
var stackPanel = new StackPanel();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,12 @@ public partial class FocusNavigationPage : Page
public FocusNavigationPage()
{
Loaded += Page_Loaded;
Unloaded += Page_Unloaded;
}

private void Page_Unloaded(object sender, Windows.UI.Xaml.RoutedEventArgs e)
{
_loadingTaskCompletionSource = new TaskCompletionSource<object>();
}

private void Page_Loaded(object sender, Windows.UI.Xaml.RoutedEventArgs e)
Expand Down
38 changes: 19 additions & 19 deletions src/Uno.UI/UI/Xaml/Controls/Frame/Frame.cs
Original file line number Diff line number Diff line change
Expand Up @@ -357,7 +357,10 @@ private bool InnerNavigateUnsafe(PageStackEntry entry, NavigationMode mode)
CurrentEntry.Instance = page;
}

UnfocusCurrentPage();
using (var leavingDisposable = MarkCurrentPageLeaving())
{
MoveFocusFromCurrent();
}

Content = CurrentEntry.Instance;

Expand Down Expand Up @@ -403,8 +406,6 @@ private bool InnerNavigateUnsafe(PageStackEntry entry, NavigationMode mode)

Navigated?.Invoke(this, navigationEvent);

FocusCurrentPage();

return true;
}

Expand Down Expand Up @@ -463,35 +464,34 @@ private void OnNavigationStopped(PageStackEntry entry, NavigationMode mode)
));
}

private void UnfocusCurrentPage()
private IDisposable MarkCurrentPageLeaving()
{
var focusManager = VisualTree.GetFocusManagerForElement(this);
if (focusManager?.FocusedElement is not { } focusedElement)
if (Content is Page page)
{
return;
}

var isWithinCurrentPage = focusedElement.GetParents().Any(p => p == this);
if (isWithinCurrentPage)
{
focusManager.ClearFocus();
page.IsLeavingFrame = true;
return Disposable.Create(() => page.IsLeavingFrame = false);
}
return Disposable.Empty;
}

private void FocusCurrentPage()
private void MoveFocusFromCurrent()
{
var focusManager = VisualTree.GetFocusManagerForElement(this);
if (focusManager is null)
if (focusManager?.FocusedElement is not { } focusedElement)
{
return;
}

var focused = focusManager.FocusedElement;
var inCurrentPage = focusedElement.GetParents().Any(p => p == this);

if (focused is null && Content is Page page)
if (inCurrentPage)
{
// Try to set focus on the page
page.TryInitialFocus();
// Set the focus on the next focusable element.
// If we remove the currently focused element from the live tree, inside a GettingFocus or LosingFocus handler,
// we failfast. This is being tracked by Bug 9840123
focusManager.SetFocusOnNextFocusableElement(FocusState, true);

(focusedElement as Control)?.UpdateFocusState(FocusState.Unfocused);
}
}
}
Expand Down
2 changes: 2 additions & 0 deletions src/Uno.UI/UI/Xaml/Controls/Page/Page.cs
Original file line number Diff line number Diff line change
Expand Up @@ -91,5 +91,7 @@ protected override void OnBackgroundChanged(DependencyPropertyChangedEventArgs e
{
UpdateBorder();
}

internal bool IsLeavingFrame { get; set; }
}
}
7 changes: 1 addition & 6 deletions src/Uno.UI/UI/Xaml/Controls/Page/Page.mux.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,6 @@ private protected override void OnLoaded()
{
base.OnLoaded();

TryInitialFocus();
}

public void TryInitialFocus()
{
var spCurrentFocusedElement = this.GetFocusedElement();

var focusManager = VisualTree.GetFocusManagerForElement(this);
Expand Down Expand Up @@ -55,7 +50,7 @@ public void TryInitialFocus()
focusManager.InitialFocus = true;

TrySetFocusedElement(spFirstFocusableElementDO);

focusManager.InitialFocus = false;
}

Expand Down
7 changes: 7 additions & 0 deletions src/Uno.UI/UI/Xaml/UIElement.mux.cs
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,13 @@ internal bool AreAllAncestorsVisible()
return false;
}

// TODO Uno specific: IsLeaving is not yet implemented on visual tree level,
// so we check if the Page is being navigated away from here instead.
if (pNext is Page page && page.IsLeavingFrame)
{
return false;
}

pElement = pNext;
}

Expand Down

0 comments on commit ee211c9

Please sign in to comment.