Browse Source

Merge branch 'master' into fixes/virtualizing-null-recycle-key

pull/11421/head
Steven Kirk 3 years ago
committed by GitHub
parent
commit
fce83ca17e
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 4
      src/Avalonia.Base/Input/AccessKeyHandler.cs
  2. 56
      src/Avalonia.Base/Input/FocusManager.cs
  3. 36
      src/Avalonia.Base/Input/IFocusManager.cs
  4. 3
      src/Avalonia.Base/Input/IFocusScope.cs
  5. 4
      src/Avalonia.Base/Input/IInputElement.cs
  6. 8
      src/Avalonia.Base/Input/IInputRoot.cs
  7. 8
      src/Avalonia.Base/Input/IKeyboardDevice.cs
  8. 17
      src/Avalonia.Base/Input/InputElement.cs
  9. 4
      src/Avalonia.Base/Input/KeyboardDevice.cs
  10. 4
      src/Avalonia.Base/Input/KeyboardNavigationHandler.cs
  11. 2
      src/Avalonia.Base/Input/MouseDevice.cs
  12. 6
      src/Avalonia.Base/Input/Navigation/TabNavigation.cs
  13. 2
      src/Avalonia.Base/Input/PenDevice.cs
  14. 2
      src/Avalonia.Base/Input/TouchDevice.cs
  15. 5
      src/Avalonia.Controls.DataGrid/DataGrid.cs
  16. 2
      src/Avalonia.Controls.ItemsRepeater/Controls/ViewManager.cs
  17. 2
      src/Avalonia.Controls/AutoCompleteBox/AutoCompleteBox.cs
  18. 2
      src/Avalonia.Controls/Calendar/Calendar.cs
  19. 3
      src/Avalonia.Controls/ComboBox.cs
  20. 4
      src/Avalonia.Controls/ContextMenu.cs
  21. 11
      src/Avalonia.Controls/DateTimePickers/DatePickerPresenter.cs
  22. 6
      src/Avalonia.Controls/DateTimePickers/TimePickerPresenter.cs
  23. 4
      src/Avalonia.Controls/Flyouts/PopupFlyoutBase.cs
  24. 11
      src/Avalonia.Controls/ItemsControl.cs
  25. 6
      src/Avalonia.Controls/Primitives/Popup.cs
  26. 5
      src/Avalonia.Controls/TopLevel.cs
  27. 3
      src/Avalonia.Controls/TreeView.cs
  28. 2
      src/Avalonia.Controls/TreeViewItem.cs
  29. 4
      src/Avalonia.Controls/WindowBase.cs
  30. 8
      src/Avalonia.Diagnostics/Diagnostics/DevTools.cs
  31. 2
      src/Linux/Avalonia.LinuxFramebuffer/LinuxFramebufferPlatform.cs
  32. 6
      src/Markup/Avalonia.Markup.Xaml/XamlIl/Runtime/XamlIlRuntimeHelpers.cs
  33. 2
      src/Windows/Avalonia.Win32.Interop/WinForms/WinFormsAvaloniaControlHost.cs
  34. 2
      src/Windows/Avalonia.Win32/Input/WindowsKeyboardDevice.cs
  35. 58
      tests/Avalonia.Base.UnitTests/Input/InputElement_Focus.cs
  36. 4
      tests/Avalonia.Base.UnitTests/Input/PointerOverTests.cs
  37. 10
      tests/Avalonia.Controls.UnitTests/FlyoutTests.cs
  38. 6
      tests/Avalonia.Controls.UnitTests/ItemsControlTests.cs
  39. 8
      tests/Avalonia.Controls.UnitTests/ListBoxTests.cs
  40. 4
      tests/Avalonia.Controls.UnitTests/Platform/DefaultMenuInteractionHandlerTests.cs
  41. 11
      tests/Avalonia.Controls.UnitTests/Primitives/PopupTests.cs
  42. 8
      tests/Avalonia.Controls.UnitTests/TabControlTests.cs
  43. 16
      tests/Avalonia.Controls.UnitTests/TreeViewTests.cs
  44. 4
      tests/Avalonia.LeakTests/ControlTests.cs
  45. 1
      tests/Avalonia.UnitTests/TestRoot.cs

4
src/Avalonia.Base/Input/AccessKeyHandler.cs

@ -141,9 +141,11 @@ namespace Avalonia.Input
if (MainMenu == null || !MainMenu.IsOpen)
{
var focusManager = FocusManager.GetFocusManager(e.Source as IInputElement);
// TODO: Use FocusScopes to store the current element and restore it when context menu is closed.
// Save currently focused input element.
_restoreFocusElement = FocusManager.Instance?.Current;
_restoreFocusElement = focusManager?.GetFocusedElement();
// When Alt is pressed without a main menu, or with a closed main menu, show
// access key markers in the window (i.e. "_File").

56
src/Avalonia.Base/Input/FocusManager.cs

@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.Linq;
using System.Runtime.CompilerServices;
using Avalonia.Interactivity;
using Avalonia.Metadata;
using Avalonia.VisualTree;
namespace Avalonia.Input
@ -10,6 +11,7 @@ namespace Avalonia.Input
/// <summary>
/// Manages focus for the application.
/// </summary>
[PrivateApi]
public class FocusManager : IFocusManager
{
/// <summary>
@ -29,15 +31,12 @@ namespace Avalonia.Input
RoutingStrategies.Tunnel);
}
/// <summary>
/// Gets the instance of the <see cref="IFocusManager"/>.
/// </summary>
public static IFocusManager? Instance => AvaloniaLocator.Current.GetService<IFocusManager>();
private IInputElement? Current => KeyboardDevice.Instance?.FocusedElement;
/// <summary>
/// Gets the currently focused <see cref="IInputElement"/>.
/// </summary>
public IInputElement? Current => KeyboardDevice.Instance?.FocusedElement;
public IInputElement? GetFocusedElement() => Current;
/// <summary>
/// Gets the current focus scope.
@ -54,7 +53,7 @@ namespace Avalonia.Input
/// <param name="control">The control to focus.</param>
/// <param name="method">The method by which focus was changed.</param>
/// <param name="keyModifiers">Any key modifiers active at the time of focus.</param>
public void Focus(
public bool Focus(
IInputElement? control,
NavigationMethod method = NavigationMethod.Unspecified,
KeyModifiers keyModifiers = KeyModifiers.None)
@ -67,7 +66,7 @@ namespace Avalonia.Input
if (scope != null)
{
Scope = scope;
SetFocusedElement(scope, control, method, keyModifiers);
return SetFocusedElement(scope, control, method, keyModifiers);
}
}
else if (Current != null)
@ -79,28 +78,29 @@ namespace Avalonia.Input
_focusScopes.TryGetValue(scope, out var element) &&
element != null)
{
Focus(element, method);
return;
return Focus(element, method);
}
}
if (Scope is object)
{
// Couldn't find a focus scope, clear focus.
SetFocusedElement(Scope, null);
return SetFocusedElement(Scope, null);
}
}
return false;
}
public IInputElement? GetFocusedElement(IInputElement e)
public void ClearFocus()
{
if (e is IFocusScope scope)
{
_focusScopes.TryGetValue(scope, out var result);
return result;
}
Focus(null);
}
return null;
public IInputElement? GetFocusedElement(IFocusScope scope)
{
_focusScopes.TryGetValue(scope, out var result);
return result;
}
/// <summary>
@ -114,7 +114,7 @@ namespace Avalonia.Input
/// If the specified scope is the current <see cref="Scope"/> then the keyboard focus
/// will change.
/// </remarks>
public void SetFocusedElement(
public bool SetFocusedElement(
IFocusScope scope,
IInputElement? element,
NavigationMethod method = NavigationMethod.Unspecified,
@ -124,7 +124,7 @@ namespace Avalonia.Input
if (element is not null && !CanFocus(element))
{
return;
return false;
}
if (_focusScopes.TryGetValue(scope, out var existingElement))
@ -144,6 +144,8 @@ namespace Avalonia.Input
{
KeyboardDevice.Instance?.SetFocusedElement(element, method, keyModifiers);
}
return true;
}
/// <summary>
@ -185,6 +187,20 @@ namespace Avalonia.Input
public static bool GetIsFocusScope(IInputElement e) => e is IFocusScope;
/// <summary>
/// Public API customers should use TopLevel.GetTopLevel(control).FocusManager.
/// But since we have split projects, we can't access TopLevel from Avalonia.Base.
/// That's why we need this helper method instead.
/// </summary>
internal static FocusManager? GetFocusManager(IInputElement? element)
{
// Element might not be a visual, and not attached to the root.
// But IFocusManager is always expected to be a FocusManager.
return (FocusManager?)((element as Visual)?.VisualRoot as IInputRoot)?.FocusManager
// In our unit tests some elements might not have a root. Remove when we migrate to headless tests.
?? (FocusManager?)AvaloniaLocator.Current.GetService<IFocusManager>();
}
/// <summary>
/// Checks if the specified element can be focused.
/// </summary>
@ -237,7 +253,7 @@ namespace Avalonia.Input
{
if (element is IInputElement inputElement && CanFocus(inputElement))
{
Instance?.Focus(inputElement, NavigationMethod.Pointer, ev.KeyModifiers);
inputElement.Focus(NavigationMethod.Pointer, ev.KeyModifiers);
break;
}

36
src/Avalonia.Base/Input/IFocusManager.cs

@ -11,40 +11,12 @@ namespace Avalonia.Input
/// <summary>
/// Gets the currently focused <see cref="IInputElement"/>.
/// </summary>
IInputElement? Current { get; }
IInputElement? GetFocusedElement();
/// <summary>
/// Gets the current focus scope.
/// Clears currently focused element.
/// </summary>
IFocusScope? Scope { get; }
/// <summary>
/// Focuses a control.
/// </summary>
/// <param name="control">The control to focus.</param>
/// <param name="method">The method by which focus was changed.</param>
/// <param name="keyModifiers">Any key modifiers active at the time of focus.</param>
void Focus(
IInputElement? control,
NavigationMethod method = NavigationMethod.Unspecified,
KeyModifiers keyModifiers = KeyModifiers.None);
/// <summary>
/// Notifies the focus manager of a change in focus scope.
/// </summary>
/// <param name="scope">The new focus scope.</param>
/// <remarks>
/// This should not be called by client code. It is called by an <see cref="IFocusScope"/>
/// when it activates, e.g. when a Window is activated.
/// </remarks>
void SetFocusScope(IFocusScope scope);
/// <summary>
/// Notifies the focus manager that a focus scope has been removed.
/// </summary>
/// <param name="scope">The focus scope to be removed.</param>
/// This should not be called by client code. It is called by an <see cref="IFocusScope"/>
/// when it deactivates or closes, e.g. when a Window is closed.
void RemoveFocusScope(IFocusScope scope);
[Unstable("This API might be removed in 11.x minor updates. Please consider focusing another element instead of removing focus at all for better UX.")]
void ClearFocus();
}
}

3
src/Avalonia.Base/Input/IFocusScope.cs

@ -1,5 +1,8 @@
using Avalonia.Metadata;
namespace Avalonia.Input
{
[NotClientImplementable]
public interface IFocusScope
{
}

4
src/Avalonia.Base/Input/IInputElement.cs

@ -119,7 +119,9 @@ namespace Avalonia.Input
/// <summary>
/// Focuses the control.
/// </summary>
void Focus();
/// <param name="method">The method by which focus was changed.</param>
/// <param name="keyModifiers">Any key modifiers active at the time of focus.</param>
bool Focus(NavigationMethod method = NavigationMethod.Unspecified, KeyModifiers keyModifiers = KeyModifiers.None);
/// <summary>
/// Gets the key bindings for the element.

8
src/Avalonia.Base/Input/IInputRoot.cs

@ -18,6 +18,14 @@ namespace Avalonia.Input
/// </summary>
IKeyboardNavigationHandler KeyboardNavigationHandler { get; }
/// <summary>
/// Gets focus manager of the root.
/// </summary>
/// <remarks>
/// Focus manager can be null only if application wasn't initialized yet.
/// </remarks>
IFocusManager? FocusManager { get; }
/// <summary>
/// Gets or sets the input element that the pointer is currently over.
/// </summary>

8
src/Avalonia.Base/Input/IKeyboardDevice.cs

@ -44,13 +44,7 @@ namespace Avalonia.Input
}
[NotClientImplementable]
public interface IKeyboardDevice : IInputDevice, INotifyPropertyChanged
public interface IKeyboardDevice : IInputDevice
{
IInputElement? FocusedElement { get; }
void SetFocusedElement(
IInputElement? element,
NavigationMethod method,
KeyModifiers modifiers);
}
}

17
src/Avalonia.Base/Input/InputElement.cs

@ -458,9 +458,10 @@ namespace Avalonia.Input
SetAndRaise(IsEffectivelyEnabledProperty, ref _isEffectivelyEnabled, value);
PseudoClasses.Set(":disabled", !value);
if (!IsEffectivelyEnabled && FocusManager.Instance?.Current == this)
if (!IsEffectivelyEnabled && FocusManager.GetFocusManager(this) is {} focusManager
&& Equals(focusManager.GetFocusedElement(), this))
{
FocusManager.Instance?.Focus(null);
focusManager.ClearFocus();
}
}
}
@ -491,12 +492,10 @@ namespace Avalonia.Input
public GestureRecognizerCollection GestureRecognizers
=> _gestureRecognizers ?? (_gestureRecognizers = new GestureRecognizerCollection(this));
/// <summary>
/// Focuses the control.
/// </summary>
public void Focus()
/// <inheritdoc />
public bool Focus(NavigationMethod method = NavigationMethod.Unspecified, KeyModifiers keyModifiers = KeyModifiers.None)
{
FocusManager.Instance?.Focus(this);
return FocusManager.GetFocusManager(this)?.Focus(this, method, keyModifiers) ?? false;
}
/// <inheritdoc/>
@ -506,7 +505,7 @@ namespace Avalonia.Input
if (IsFocused)
{
FocusManager.Instance?.Focus(null);
FocusManager.GetFocusManager(this)?.ClearFocus();
}
}
@ -649,7 +648,7 @@ namespace Avalonia.Input
}
else if (change.Property == IsVisibleProperty && !change.GetNewValue<bool>() && IsFocused)
{
FocusManager.Instance?.Focus(null);
FocusManager.GetFocusManager(this)?.ClearFocus();
}
}

4
src/Avalonia.Base/Input/KeyboardDevice.cs

@ -3,9 +3,11 @@ using System.Runtime.CompilerServices;
using Avalonia.Input.Raw;
using Avalonia.Input.TextInput;
using Avalonia.Interactivity;
using Avalonia.Metadata;
namespace Avalonia.Input
{
[PrivateApi]
public class KeyboardDevice : IKeyboardDevice, INotifyPropertyChanged
{
private IInputElement? _focusedElement;
@ -13,7 +15,7 @@ namespace Avalonia.Input
public event PropertyChangedEventHandler? PropertyChanged;
public static IKeyboardDevice? Instance => AvaloniaLocator.Current.GetService<IKeyboardDevice>();
internal static KeyboardDevice? Instance => AvaloniaLocator.Current.GetService<IKeyboardDevice>() as KeyboardDevice;
public IInputManager? InputManager => AvaloniaLocator.Current.GetService<IInputManager>();

4
src/Avalonia.Base/Input/KeyboardNavigationHandler.cs

@ -88,7 +88,7 @@ namespace Avalonia.Input
var method = direction == NavigationDirection.Next ||
direction == NavigationDirection.Previous ?
NavigationMethod.Tab : NavigationMethod.Directional;
FocusManager.Instance?.Focus(next, method, keyModifiers);
next.Focus(method, keyModifiers);
}
}
@ -99,7 +99,7 @@ namespace Avalonia.Input
/// <param name="e">The event args.</param>
protected virtual void OnKeyDown(object? sender, KeyEventArgs e)
{
var current = FocusManager.Instance?.Current;
var current = FocusManager.GetFocusManager(e.Source as IInputElement)?.GetFocusedElement();
if (current != null && e.Key == Key.Tab)
{

2
src/Avalonia.Base/Input/MouseDevice.cs

@ -2,6 +2,7 @@ using System;
using System.Collections.Generic;
using Avalonia.Reactive;
using Avalonia.Input.Raw;
using Avalonia.Metadata;
using Avalonia.Platform;
using Avalonia.Utilities;
#pragma warning disable CS0618
@ -11,6 +12,7 @@ namespace Avalonia.Input
/// <summary>
/// Represents a mouse device.
/// </summary>
[PrivateApi]
public class MouseDevice : IMouseDevice, IDisposable
{
private int _clickCount;

6
src/Avalonia.Base/Input/Navigation/TabNavigation.cs

@ -190,9 +190,11 @@ namespace Avalonia.Input.Navigation
private static IInputElement? FocusedElement(IInputElement? e)
{
// Focus delegation is enabled only if keyboard focus is outside the container
if (e != null && !e.IsKeyboardFocusWithin)
if (e != null && !e.IsKeyboardFocusWithin && e is IFocusScope scope)
{
var focusedElement = (FocusManager.Instance as FocusManager)?.GetFocusedElement(e);
var focusManager = FocusManager.GetFocusManager(e);
var focusedElement = focusManager?.GetFocusedElement(scope);
if (focusedElement != null)
{
if (!IsFocusScope(e))

2
src/Avalonia.Base/Input/PenDevice.cs

@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using Avalonia.Input.Raw;
using Avalonia.Metadata;
using Avalonia.Platform;
#pragma warning disable CS0618
@ -11,6 +12,7 @@ namespace Avalonia.Input
/// <summary>
/// Represents a pen/stylus device.
/// </summary>
[PrivateApi]
public class PenDevice : IPenDevice, IDisposable
{
private readonly Dictionary<long, Pointer> _pointers = new();

2
src/Avalonia.Base/Input/TouchDevice.cs

@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using Avalonia.Input.Raw;
using Avalonia.Metadata;
using Avalonia.Platform;
#pragma warning disable CS0618
@ -14,6 +15,7 @@ namespace Avalonia.Input
/// <remarks>
/// This class is supposed to be used on per-toplevel basis, don't use a shared one
/// </remarks>
[PrivateApi]
public class TouchDevice : IPointerDevice, IDisposable
{
private readonly Dictionary<long, Pointer> _pointers = new Dictionary<long, Pointer>();

5
src/Avalonia.Controls.DataGrid/DataGrid.cs

@ -3958,7 +3958,7 @@ namespace Avalonia.Controls
{
bool focusLeftDataGrid = true;
bool dataGridWillReceiveRoutedEvent = true;
Visual focusedObject = FocusManager.Instance.Current as Visual;
Visual focusedObject = FocusManager.GetFocusManager(this)?.GetFocusedElement() as Visual;
DataGridColumn editingColumn = null;
while (focusedObject != null)
@ -4865,7 +4865,8 @@ namespace Avalonia.Controls
if (!ctrl)
{
// If Enter was used by a TextBox, we shouldn't handle the key
if (FocusManager.Instance.Current is TextBox focusedTextBox && focusedTextBox.AcceptsReturn)
if (FocusManager.GetFocusManager(this)?.GetFocusedElement() is TextBox focusedTextBox
&& focusedTextBox.AcceptsReturn)
{
return false;
}

2
src/Avalonia.Controls.ItemsRepeater/Controls/ViewManager.cs

@ -695,7 +695,7 @@ namespace Avalonia.Controls
{
Control? focusedElement = null;
if (FocusManager.Instance?.Current is Visual child)
if (TopLevel.GetTopLevel(_owner)?.FocusManager?.GetFocusedElement() is Visual child)
{
var parent = child.GetVisualParent();
var owner = _owner;

2
src/Avalonia.Controls/AutoCompleteBox/AutoCompleteBox.cs

@ -762,7 +762,7 @@ namespace Avalonia.Controls
/// otherwise, false.</returns>
protected bool HasFocus()
{
Visual? focused = FocusManager.Instance?.Current as Visual;
Visual? focused = FocusManager.GetFocusManager(this)?.GetFocusedElement() as Visual;
while (focused != null)
{

2
src/Avalonia.Controls/Calendar/Calendar.cs

@ -1567,7 +1567,7 @@ namespace Avalonia.Controls
base.OnPointerReleased(e);
if (!HasFocusInternal && e.InitialPressMouseButton == MouseButton.Left)
{
FocusManager.Instance?.Focus(this);
Focus();
}
}

3
src/Avalonia.Controls/ComboBox.cs

@ -230,8 +230,7 @@ namespace Avalonia.Controls
var firstChild = Presenter?.Panel?.Children.FirstOrDefault(c => CanFocus(c));
if (firstChild != null)
{
FocusManager.Instance?.Focus(firstChild, NavigationMethod.Directional);
e.Handled = true;
e.Handled = firstChild.Focus(NavigationMethod.Directional);
}
}
}

4
src/Avalonia.Controls/ContextMenu.cs

@ -360,7 +360,7 @@ namespace Avalonia.Controls
private void PopupOpened(object? sender, EventArgs e)
{
_previousFocus = FocusManager.Instance?.Current;
_previousFocus = FocusManager.GetFocusManager(this)?.GetFocusedElement();
Focus();
_popupHostChangedHandler?.Invoke(_popup!.Host);
@ -390,7 +390,7 @@ namespace Avalonia.Controls
}
// HACK: Reset the focus when the popup is closed. We need to fix this so it's automatic.
FocusManager.Instance?.Focus(_previousFocus);
_previousFocus?.Focus();
RaiseEvent(new RoutedEventArgs
{

11
src/Avalonia.Controls/DateTimePickers/DatePickerPresenter.cs

@ -323,10 +323,11 @@ namespace Avalonia.Controls
e.Handled = true;
break;
case Key.Tab:
if (FocusManager.Instance?.Current is IInputElement focus)
var focusManager = FocusManager.GetFocusManager(this);
if (focusManager?.GetFocusedElement() is { } focus)
{
var nextFocus = KeyboardNavigationHandler.GetNext(focus, NavigationDirection.Next);
KeyboardDevice.Instance?.SetFocusedElement(nextFocus, NavigationMethod.Tab, KeyModifiers.None);
nextFocus?.Focus(NavigationMethod.Tab);
e.Handled = true;
}
break;
@ -449,15 +450,15 @@ namespace Avalonia.Controls
if (monthCol < dayCol && monthCol < yearCol)
{
KeyboardDevice.Instance?.SetFocusedElement(_monthSelector, NavigationMethod.Pointer, KeyModifiers.None);
_monthSelector?.Focus(NavigationMethod.Pointer);
}
else if (dayCol < monthCol && dayCol < yearCol)
{
KeyboardDevice.Instance?.SetFocusedElement(_daySelector, NavigationMethod.Pointer, KeyModifiers.None);
_monthSelector?.Focus(NavigationMethod.Pointer);
}
else if (yearCol < monthCol && yearCol < dayCol)
{
KeyboardDevice.Instance?.SetFocusedElement(_yearSelector, NavigationMethod.Pointer, KeyModifiers.None);
_yearSelector?.Focus(NavigationMethod.Pointer);
}
}

6
src/Avalonia.Controls/DateTimePickers/TimePickerPresenter.cs

@ -161,10 +161,10 @@ namespace Avalonia.Controls
e.Handled = true;
break;
case Key.Tab:
if (FocusManager.Instance?.Current is IInputElement focus)
if (FocusManager.GetFocusManager(this)?.GetFocusedElement() is { } focus)
{
var nextFocus = KeyboardNavigationHandler.GetNext(focus, NavigationDirection.Next);
KeyboardDevice.Instance?.SetFocusedElement(nextFocus, NavigationMethod.Tab, KeyModifiers.None);
nextFocus?.Focus(NavigationMethod.Tab);
e.Handled = true;
}
break;
@ -216,7 +216,7 @@ namespace Avalonia.Controls
_periodSelector.SelectedValue = hr >= 12 ? 1 : 0;
SetGrid();
KeyboardDevice.Instance?.SetFocusedElement(_hourSelector, NavigationMethod.Pointer, KeyModifiers.None);
_hourSelector?.Focus(NavigationMethod.Pointer);
}
private void SetGrid()

4
src/Avalonia.Controls/Flyouts/PopupFlyoutBase.cs

@ -250,14 +250,14 @@ namespace Avalonia.Controls.Primitives
// Try and focus content inside Flyout
if (Popup.Child.Focusable)
{
FocusManager.Instance?.Focus(Popup.Child);
Popup.Child.Focus();
}
else
{
var nextFocus = KeyboardNavigationHandler.GetNext(Popup.Child, NavigationDirection.Next);
if (nextFocus != null)
{
FocusManager.Instance?.Focus(nextFocus);
nextFocus.Focus();
}
}
}

11
src/Avalonia.Controls/ItemsControl.cs

@ -566,19 +566,20 @@ namespace Avalonia.Controls
{
if (!e.Handled)
{
var focus = FocusManager.Instance;
var focus = FocusManager.GetFocusManager(this);
var direction = e.Key.ToNavigationDirection();
var container = Presenter?.Panel as INavigableContainer;
if (container == null ||
focus?.Current == null ||
if (focus == null ||
container == null ||
focus.GetFocusedElement() == null ||
direction == null ||
direction.Value.IsTab())
{
return;
}
Visual? current = focus.Current as Visual;
Visual? current = focus.GetFocusedElement() as Visual;
while (current != null)
{
@ -588,7 +589,7 @@ namespace Avalonia.Controls
if (next != null)
{
focus.Focus(next, NavigationMethod.Directional, e.KeyModifiers);
next.Focus(NavigationMethod.Directional, e.KeyModifiers);
e.Handled = true;
}

6
src/Avalonia.Controls/Primitives/Popup.cs

@ -727,7 +727,7 @@ namespace Avalonia.Controls.Primitives
Closed?.Invoke(this, EventArgs.Empty);
var focusCheck = FocusManager.Instance?.Current;
var focusCheck = FocusManager.GetFocusManager(this)?.GetFocusedElement();
// Focus is set to null as part of popup closing, so we only want to
// set focus to PlacementTarget if this is the case
@ -744,7 +744,7 @@ namespace Avalonia.Controls.Primitives
if (e is object)
{
FocusManager.Instance?.Focus(e);
e.Focus();
}
}
else
@ -752,7 +752,7 @@ namespace Avalonia.Controls.Primitives
var anc = this.FindLogicalAncestorOfType<Control>();
if (anc != null)
{
FocusManager.Instance?.Focus(anc);
anc.Focus();
}
}
}

5
src/Avalonia.Controls/TopLevel.cs

@ -452,6 +452,9 @@ namespace Avalonia.Controls
/// </summary>
public IClipboard? Clipboard => PlatformImpl?.TryGetFeature<IClipboard>();
/// <inheritdoc />
public IFocusManager? FocusManager => AvaloniaLocator.Current.GetService<IFocusManager>();
/// <inheritdoc/>
Point IRenderRoot.PointToClient(PixelPoint p)
{
@ -725,7 +728,7 @@ namespace Avalonia.Controls
void PlatformImpl_LostFocus()
{
var focused = (Visual?)FocusManager.Instance?.Current;
var focused = (Visual?)FocusManager?.GetFocusedElement();
if (focused == null)
return;
while (focused.VisualParent != null)

3
src/Avalonia.Controls/TreeView.cs

@ -560,8 +560,7 @@ namespace Avalonia.Controls
if (next != null)
{
FocusManager.Instance?.Focus(next, NavigationMethod.Directional);
e.Handled = true;
e.Handled = next.Focus(NavigationMethod.Directional);
}
}
else

2
src/Avalonia.Controls/TreeViewItem.cs

@ -238,7 +238,7 @@ namespace Avalonia.Controls
}
else
{
FocusManager.Instance?.Focus(treeViewItem, NavigationMethod.Directional);
treeViewItem.Focus(NavigationMethod.Directional);
}
return true;

4
src/Avalonia.Controls/WindowBase.cs

@ -234,7 +234,7 @@ namespace Avalonia.Controls
if (this is IFocusScope scope)
{
FocusManager.Instance?.RemoveFocusScope(scope);
((FocusManager?)FocusManager)?.RemoveFocusScope(scope);
}
base.HandleClosed();
@ -326,7 +326,7 @@ namespace Avalonia.Controls
if (scope != null)
{
FocusManager.Instance?.SetFocusScope(scope);
((FocusManager?)FocusManager)?.SetFocusScope(scope);
}
IsActive = true;

8
src/Avalonia.Diagnostics/Diagnostics/DevTools.cs

@ -86,7 +86,7 @@ namespace Avalonia.Diagnostics
private static IDisposable Open(IDevToolsTopLevelGroup topLevelGroup, DevToolsOptions options,
Window? owner, Application? app)
{
var focussedControl = KeyboardDevice.Instance?.FocusedElement as Control;
var focusedControl = owner?.FocusManager?.GetFocusedElement() as Control;
AvaloniaObject root = topLevelGroup switch
{
ClassicDesktopStyleApplicationLifetimeTopLevelGroup gr => new Controls.Application(gr, app ?? Application.Current!),
@ -98,7 +98,7 @@ namespace Avalonia.Diagnostics
if (s_open.TryGetValue(topLevelGroup, out var mainWindow))
{
mainWindow.Activate();
mainWindow.SelectedControl(focussedControl);
mainWindow.SelectedControl(focusedControl);
return Disposable.Empty;
}
if (topLevelGroup.Items.Count == 1 && topLevelGroup.Items is not INotifyCollectionChanged)
@ -110,7 +110,7 @@ namespace Avalonia.Diagnostics
if (group.Key.Items.Contains(singleTopLevel))
{
group.Value.Activate();
group.Value.SelectedControl(focussedControl);
group.Value.SelectedControl(focusedControl);
return Disposable.Empty;
}
}
@ -124,7 +124,7 @@ namespace Avalonia.Diagnostics
Tag = topLevelGroup
};
window.SetOptions(options);
window.SelectedControl(focussedControl);
window.SelectedControl(focusedControl);
window.Closed += DevToolsClosed;
s_open.Add(topLevelGroup, window);
if (options.ShowAsChildWindow && owner is not null)

2
src/Linux/Avalonia.LinuxFramebuffer/LinuxFramebufferPlatform.cs

@ -107,7 +107,7 @@ namespace Avalonia.LinuxFramebuffer
if (_topLevel is IFocusScope scope)
{
FocusManager.Instance?.SetFocusScope(scope);
((FocusManager)_topLevel.FocusManager).SetFocusScope(scope);
}
}

6
src/Markup/Avalonia.Markup.Xaml/XamlIl/Runtime/XamlIlRuntimeHelpers.cs

@ -154,7 +154,8 @@ namespace Avalonia.Markup.Xaml.XamlIl.Runtime
var namespaces = _nsInfo.XmlNamespaces;
if (!namespaces.TryGetValue(ns, out var lst))
throw new ArgumentException("Unable to resolve namespace for type " + qualifiedTypeName);
foreach (var entry in lst)
var resolvable = lst.Where(static e => e.ClrAssemblyName is { Length: > 0 });
foreach (var entry in resolvable)
{
var asm = Assembly.Load(new AssemblyName(entry.ClrAssemblyName));
var resolved = asm.GetType(entry.ClrNamespace + "." + name);
@ -164,7 +165,8 @@ namespace Avalonia.Markup.Xaml.XamlIl.Runtime
throw new ArgumentException(
$"Unable to resolve type {qualifiedTypeName} from any of the following locations: " +
string.Join(",", lst.Select(e => $"`{e.ClrAssemblyName}:{e.ClrNamespace}.{name}`")));
string.Join(",", resolvable.Select(e => $"`clr-namespace:{e.ClrNamespace};assembly={e.ClrAssemblyName}`")))
{ HelpLink = "https://docs.avaloniaui.net/guides/basics/introduction-to-xaml#valid-xaml-namespaces" };
}
}

2
src/Windows/Avalonia.Win32.Interop/WinForms/WinFormsAvaloniaControlHost.cs

@ -22,7 +22,7 @@ namespace Avalonia.Win32.Embedding
UnmanagedMethods.SetParent(WindowHandle, Handle);
_root.Prepare();
if (_root.IsFocused)
FocusManager.Instance.Focus(null);
_root.FocusManager.ClearFocus();
_root.GotFocus += RootGotFocus;
FixPosition();

2
src/Windows/Avalonia.Win32/Input/WindowsKeyboardDevice.cs

@ -5,7 +5,7 @@ using Avalonia.Win32.Interop;
namespace Avalonia.Win32.Input
{
class WindowsKeyboardDevice : KeyboardDevice
internal class WindowsKeyboardDevice : KeyboardDevice
{
private readonly byte[] _keyStates = new byte[256];

58
tests/Avalonia.Base.UnitTests/Input/InputElement_Focus.cs

@ -23,7 +23,7 @@ namespace Avalonia.Base.UnitTests.Input
target.Focus();
Assert.Same(target, FocusManager.Instance.Current);
Assert.Same(target, root.FocusManager.GetFocusedElement());
}
}
@ -39,14 +39,14 @@ namespace Avalonia.Base.UnitTests.Input
Child = target = new Button() { IsVisible = false}
};
Assert.Null(FocusManager.Instance.Current);
Assert.Null(root.FocusManager.GetFocusedElement());
target.Focus();
Assert.False(target.IsFocused);
Assert.False(target.IsKeyboardFocusWithin);
Assert.Null(FocusManager.Instance.Current);
Assert.Null(root.FocusManager.GetFocusedElement());
}
}
@ -67,14 +67,14 @@ namespace Avalonia.Base.UnitTests.Input
}
};
Assert.Null(FocusManager.Instance.Current);
Assert.Null(root.FocusManager.GetFocusedElement());
target.Focus();
Assert.False(target.IsFocused);
Assert.False(target.IsKeyboardFocusWithin);
Assert.Null(FocusManager.Instance.Current);
Assert.Null(root.FocusManager.GetFocusedElement());
}
}
@ -100,11 +100,11 @@ namespace Avalonia.Base.UnitTests.Input
first.Focus();
Assert.Same(first, FocusManager.Instance.Current);
Assert.Same(first, root.FocusManager.GetFocusedElement());
second.Focus();
Assert.Same(first, FocusManager.Instance.Current);
Assert.Same(first, root.FocusManager.GetFocusedElement());
}
}
@ -120,14 +120,14 @@ namespace Avalonia.Base.UnitTests.Input
Child = target = new Button() { IsEnabled = false }
};
Assert.Null(FocusManager.Instance.Current);
Assert.Null(root.FocusManager.GetFocusedElement());
target.Focus();
Assert.False(target.IsFocused);
Assert.False(target.IsKeyboardFocusWithin);
Assert.Null(FocusManager.Instance.Current);
Assert.Null(root.FocusManager.GetFocusedElement());
}
}
@ -148,14 +148,14 @@ namespace Avalonia.Base.UnitTests.Input
}
};
Assert.Null(FocusManager.Instance.Current);
Assert.Null(root.FocusManager.GetFocusedElement());
target.Focus();
Assert.False(target.IsFocused);
Assert.False(target.IsKeyboardFocusWithin);
Assert.Null(FocusManager.Instance.Current);
Assert.Null(root.FocusManager.GetFocusedElement());
}
}
@ -201,7 +201,7 @@ namespace Avalonia.Base.UnitTests.Input
target.Focus();
target.IsVisible = false;
Assert.Null(FocusManager.Instance.Current);
Assert.Null(root.FocusManager.GetFocusedElement());
}
}
@ -224,7 +224,7 @@ namespace Avalonia.Base.UnitTests.Input
target.Focus();
container.IsVisible = false;
Assert.Null(FocusManager.Instance.Current);
Assert.Null(root.FocusManager.GetFocusedElement());
}
}
@ -243,7 +243,7 @@ namespace Avalonia.Base.UnitTests.Input
target.Focus();
target.IsEnabled = false;
Assert.Null(FocusManager.Instance.Current);
Assert.Null(root.FocusManager.GetFocusedElement());
}
}
@ -266,7 +266,7 @@ namespace Avalonia.Base.UnitTests.Input
target.Focus();
container.IsEnabled = false;
Assert.Null(FocusManager.Instance.Current);
Assert.Null(root.FocusManager.GetFocusedElement());
}
}
@ -285,7 +285,7 @@ namespace Avalonia.Base.UnitTests.Input
target.Focus();
root.Child = null;
Assert.Null(FocusManager.Instance.Current);
Assert.Null(root.FocusManager.GetFocusedElement());
}
}
@ -312,13 +312,13 @@ namespace Avalonia.Base.UnitTests.Input
target2.ApplyTemplate();
FocusManager.Instance?.Focus(target1);
target1.Focus();
Assert.True(target1.IsFocused);
Assert.True(target1.Classes.Contains(":focus"));
Assert.False(target2.IsFocused);
Assert.False(target2.Classes.Contains(":focus"));
FocusManager.Instance?.Focus(target2, NavigationMethod.Tab);
target2.Focus(NavigationMethod.Tab);
Assert.False(target1.IsFocused);
Assert.False(target1.Classes.Contains(":focus"));
Assert.True(target2.IsFocused);
@ -348,19 +348,19 @@ namespace Avalonia.Base.UnitTests.Input
target1.ApplyTemplate();
target2.ApplyTemplate();
FocusManager.Instance?.Focus(target1);
target1.Focus();
Assert.True(target1.IsFocused);
Assert.False(target1.Classes.Contains(":focus-visible"));
Assert.False(target2.IsFocused);
Assert.False(target2.Classes.Contains(":focus-visible"));
FocusManager.Instance?.Focus(target2, NavigationMethod.Tab);
target2.Focus(NavigationMethod.Tab);
Assert.False(target1.IsFocused);
Assert.False(target1.Classes.Contains(":focus-visible"));
Assert.True(target2.IsFocused);
Assert.True(target2.Classes.Contains(":focus-visible"));
FocusManager.Instance?.Focus(target1, NavigationMethod.Directional);
target1.Focus(NavigationMethod.Directional);
Assert.True(target1.IsFocused);
Assert.True(target1.Classes.Contains(":focus-visible"));
Assert.False(target2.IsFocused);
@ -390,7 +390,7 @@ namespace Avalonia.Base.UnitTests.Input
target1.ApplyTemplate();
target2.ApplyTemplate();
FocusManager.Instance?.Focus(target1);
target1.Focus();
Assert.True(target1.IsFocused);
Assert.True(target1.Classes.Contains(":focus-within"));
Assert.True(target1.IsKeyboardFocusWithin);
@ -425,7 +425,7 @@ namespace Avalonia.Base.UnitTests.Input
target1.ApplyTemplate();
target2.ApplyTemplate();
FocusManager.Instance?.Focus(target1);
target1.Focus();
Assert.True(target1.IsFocused);
Assert.True(target1.Classes.Contains(":focus-within"));
Assert.True(target1.IsKeyboardFocusWithin);
@ -436,7 +436,7 @@ namespace Avalonia.Base.UnitTests.Input
Assert.True(root.Classes.Contains(":focus-within"));
Assert.True(root.IsKeyboardFocusWithin);
FocusManager.Instance?.Focus(target2);
target2.Focus();
Assert.False(target1.IsFocused);
Assert.False(target1.Classes.Contains(":focus-within"));
@ -478,7 +478,7 @@ namespace Avalonia.Base.UnitTests.Input
target1.ApplyTemplate();
target2.ApplyTemplate();
FocusManager.Instance?.Focus(target1);
target1.Focus();
Assert.True(target1.IsFocused);
Assert.True(target1.Classes.Contains(":focus-within"));
Assert.True(target1.IsKeyboardFocusWithin);
@ -534,7 +534,7 @@ namespace Avalonia.Base.UnitTests.Input
target1.ApplyTemplate();
target2.ApplyTemplate();
FocusManager.Instance?.Focus(target1);
target1.Focus();
Assert.True(target1.IsFocused);
Assert.True(target1.Classes.Contains(":focus-within"));
Assert.True(target1.IsKeyboardFocusWithin);
@ -545,7 +545,7 @@ namespace Avalonia.Base.UnitTests.Input
Assert.Equal(KeyboardDevice.Instance.FocusedElement, target1);
FocusManager.Instance?.Focus(target2);
target2.Focus();
Assert.False(target1.IsFocused);
Assert.False(target1.Classes.Contains(":focus-within"));
@ -578,9 +578,9 @@ namespace Avalonia.Base.UnitTests.Input
};
target.Focus();
FocusManager.Instance.Focus(null);
root.FocusManager.ClearFocus();
Assert.Null(FocusManager.Instance.Current);
Assert.Null(root.FocusManager.GetFocusedElement());
}
}
}

4
tests/Avalonia.Base.UnitTests/Input/PointerOverTests.cs

@ -20,7 +20,9 @@ namespace Avalonia.Base.UnitTests.Input
[Fact]
public void Close_Should_Remove_PointerOver()
{
using var app = UnitTestApplication.Start(new TestServices(inputManager: new InputManager()));
using var app = UnitTestApplication.Start(new TestServices(
inputManager: new InputManager(),
focusManager: new FocusManager()));
var renderer = RendererMocks.CreateRenderer();
var device = CreatePointerDeviceMock().Object;

10
tests/Avalonia.Controls.UnitTests/FlyoutTests.cs

@ -288,10 +288,10 @@ namespace Avalonia.Controls.UnitTests
window.Show();
button.Focus();
Assert.True(FocusManager.Instance?.Current == button);
Assert.True(window.FocusManager.GetFocusedElement() == button);
button.Flyout.ShowAt(button);
Assert.False(button.IsFocused);
Assert.True(FocusManager.Instance?.Current == flyoutTextBox);
Assert.True(window.FocusManager.GetFocusedElement() == flyoutTextBox);
}
}
@ -322,10 +322,10 @@ namespace Avalonia.Controls.UnitTests
window.Content = button;
window.Show();
FocusManager.Instance?.Focus(button);
Assert.True(FocusManager.Instance?.Current == button);
button.Focus();
Assert.True(window.FocusManager.GetFocusedElement() == button);
button.Flyout.ShowAt(button);
Assert.True(FocusManager.Instance?.Current == button);
Assert.True(window.FocusManager.GetFocusedElement() == button);
}
}

6
tests/Avalonia.Controls.UnitTests/ItemsControlTests.cs

@ -576,8 +576,9 @@ namespace Avalonia.Controls.UnitTests
});
var panel = Assert.IsAssignableFrom<Panel>(target.ItemsPanelRoot);
var focusManager = ((IInputRoot)target.VisualRoot!).FocusManager;
Assert.Equal(panel.Children[1], FocusManager.Instance!.Current);
Assert.Equal(panel.Children[1], focusManager?.GetFocusedElement());
}
[Fact]
@ -601,8 +602,9 @@ namespace Avalonia.Controls.UnitTests
});
var panel = Assert.IsAssignableFrom<Panel>(target.ItemsPanelRoot);
var focusManager = ((IInputRoot)target.VisualRoot!).FocusManager;
Assert.Equal(panel.Children[2], FocusManager.Instance!.Current);
Assert.Equal(panel.Children[2], focusManager?.GetFocusedElement());
}
[Fact]

8
tests/Avalonia.Controls.UnitTests/ListBoxTests.cs

@ -979,7 +979,7 @@ namespace Avalonia.Controls.UnitTests
RaiseKeyEvent(button, Key.Tab);
var item = target.ContainerFromIndex(0);
Assert.Same(item, FocusManager.Instance.Current);
Assert.Same(item, root.FocusManager.GetFocusedElement());
}
[Fact]
@ -1026,17 +1026,17 @@ namespace Avalonia.Controls.UnitTests
RaiseKeyEvent(button, Key.Tab);
var item = target.ContainerFromIndex(1);
Assert.Same(item, FocusManager.Instance.Current);
Assert.Same(item, root.FocusManager.GetFocusedElement());
RaiseKeyEvent(item, Key.Tab);
Assert.Same(button, FocusManager.Instance.Current);
Assert.Same(button, root.FocusManager.GetFocusedElement());
target.Selection.AnchorIndex = 2;
RaiseKeyEvent(button, Key.Tab);
item = target.ContainerFromIndex(2);
Assert.Same(item, FocusManager.Instance.Current);
Assert.Same(item, root.FocusManager.GetFocusedElement());
}
private static void RaiseKeyEvent(Control target, Key key, KeyModifiers inputModifiers = 0)

4
tests/Avalonia.Controls.UnitTests/Platform/DefaultMenuInteractionHandlerTests.cs

@ -267,7 +267,7 @@ namespace Avalonia.Controls.UnitTests.Platform
target.KeyDown(item.Object, e);
parentItem.Verify(x => x.Close());
parentItem.Verify(x => x.Focus());
parentItem.Verify(x => x.Focus(It.IsAny<NavigationMethod>(), It.IsAny<KeyModifiers>()));
Assert.True(e.Handled);
}
@ -351,7 +351,7 @@ namespace Avalonia.Controls.UnitTests.Platform
target.KeyDown(item.Object, e);
parentItem.Verify(x => x.Close());
parentItem.Verify(x => x.Focus());
parentItem.Verify(x => x.Focus(It.IsAny<NavigationMethod>(), It.IsAny<KeyModifiers>()));
Assert.True(e.Handled);
}

11
tests/Avalonia.Controls.UnitTests/Primitives/PopupTests.cs

@ -642,10 +642,11 @@ namespace Avalonia.Controls.UnitTests.Primitives
tb.Focus();
Assert.True(FocusManager.Instance?.Current == tb);
var focusManager = TopLevel.GetTopLevel(tb)!.FocusManager;
tb = Assert.IsType<TextBox>(focusManager.GetFocusedElement());
//Ensure focus remains in the popup
var nextFocus = KeyboardNavigationHandler.GetNext(FocusManager.Instance.Current, NavigationDirection.Next);
var nextFocus = KeyboardNavigationHandler.GetNext(tb, NavigationDirection.Next);
Assert.True(nextFocus == b);
@ -684,7 +685,8 @@ namespace Avalonia.Controls.UnitTests.Primitives
p.Close();
var focus = FocusManager.Instance?.Current;
var focusManager = window.FocusManager;
var focus = focusManager.GetFocusedElement();
Assert.True(focus == window);
}
}
@ -723,7 +725,8 @@ namespace Avalonia.Controls.UnitTests.Primitives
windowTB.Focus();
var focus = FocusManager.Instance?.Current;
var focusManager = window.FocusManager;
var focus = focusManager.GetFocusedElement();
Assert.True(focus == windowTB);

8
tests/Avalonia.Controls.UnitTests/TabControlTests.cs

@ -461,7 +461,7 @@ namespace Avalonia.Controls.UnitTests
RaiseKeyEvent(button, Key.Tab);
var item = target.ContainerFromIndex(0);
Assert.Same(item, FocusManager.Instance.Current);
Assert.Same(item, root.FocusManager.GetFocusedElement());
}
[Fact]
@ -513,17 +513,17 @@ namespace Avalonia.Controls.UnitTests
RaiseKeyEvent(button, Key.Tab);
var item = target.ContainerFromIndex(1);
Assert.Same(item, FocusManager.Instance.Current);
Assert.Same(item, root.FocusManager.GetFocusedElement());
RaiseKeyEvent(item, Key.Tab);
Assert.Same(button, FocusManager.Instance.Current);
Assert.Same(button, root.FocusManager.GetFocusedElement());
target.Selection.AnchorIndex = 2;
RaiseKeyEvent(button, Key.Tab);
item = target.ContainerFromIndex(2);
Assert.Same(item, FocusManager.Instance.Current);
Assert.Same(item, root.FocusManager.GetFocusedElement());
}
private static IControlTemplate TabControlTemplate()

16
tests/Avalonia.Controls.UnitTests/TreeViewTests.cs

@ -969,7 +969,6 @@ namespace Avalonia.Controls.UnitTests
public void Keyboard_Navigation_Should_Move_To_Last_Selected_Node()
{
using var app = Start();
var focus = FocusManager.Instance!;
var navigation = AvaloniaLocator.Current.GetRequiredService<IKeyboardNavigationHandler>();
var data = CreateTestTreeData();
@ -984,6 +983,7 @@ namespace Avalonia.Controls.UnitTests
{
Children = { target, button },
});
var focus = root.FocusManager;
root.LayoutManager.ExecuteInitialLayoutPass();
ExpandAll(target);
@ -994,20 +994,19 @@ namespace Avalonia.Controls.UnitTests
target.SelectedItem = item;
node.Focus();
Assert.Same(node, focus.Current);
Assert.Same(node, focus.GetFocusedElement());
navigation.Move(focus.Current!, NavigationDirection.Next);
Assert.Same(button, focus.Current);
navigation.Move(focus.GetFocusedElement()!, NavigationDirection.Next);
Assert.Same(button, focus.GetFocusedElement());
navigation.Move(focus.Current!, NavigationDirection.Next);
Assert.Same(node, focus.Current);
navigation.Move(focus.GetFocusedElement()!, NavigationDirection.Next);
Assert.Same(node, focus.GetFocusedElement());
}
[Fact]
public void Keyboard_Navigation_Should_Not_Crash_If_Selected_Item_Is_not_In_Tree()
{
using var app = Start();
var focus = FocusManager.Instance!;
var data = CreateTestTreeData();
var selectedNode = new Node { Value = "Out of Tree Selected Item" };
@ -1025,6 +1024,7 @@ namespace Avalonia.Controls.UnitTests
{
Children = { target, button },
});
var focus = root.FocusManager;
root.LayoutManager.ExecuteInitialLayoutPass();
ExpandAll(target);
@ -1035,7 +1035,7 @@ namespace Avalonia.Controls.UnitTests
target.SelectedItem = selectedNode;
node.Focus();
Assert.Same(node, focus.Current);
Assert.Same(node, focus.GetFocusedElement());
}
[Fact]

4
tests/Avalonia.LeakTests/ControlTests.cs

@ -561,7 +561,7 @@ namespace Avalonia.LeakTests
var window = new Window { Focusable = true };
window.Show();
Assert.Same(window, FocusManager.Instance.Current);
Assert.Same(window, window.FocusManager.GetFocusedElement());
// Context menu in resources means the baseline may not be 0.
var initialMenuCount = 0;
@ -608,7 +608,7 @@ namespace Avalonia.LeakTests
var window = new Window { Focusable = true };
window.Show();
Assert.Same(window, FocusManager.Instance.Current);
Assert.Same(window, window.FocusManager.GetFocusedElement());
// Context menu in resources means the baseline may not be 0.
var initialMenuCount = 0;

1
tests/Avalonia.UnitTests/TestRoot.cs

@ -54,6 +54,7 @@ namespace Avalonia.UnitTests
public IAccessKeyHandler AccessKeyHandler => null;
public IKeyboardNavigationHandler KeyboardNavigationHandler => null;
public IFocusManager FocusManager => AvaloniaLocator.Current.GetService<IFocusManager>();
public IInputElement PointerOverElement { get; set; }

Loading…
Cancel
Save