Browse Source
fix: Navigation when CanExecute is fasle (#13507)
* test: Add test navigation with CanExecute is False
* fix: Navigation when CanExecute is false
UnsafeAsSpan-logical-children
workgroupengineering
3 years ago
committed by
GitHub
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with
61 additions and
15 deletions
-
src/Avalonia.Base/Input/Navigation/TabNavigation.cs
-
tests/Avalonia.Base.UnitTests/Input/KeyboardDeviceTests.cs
-
tests/Avalonia.Base.UnitTests/Input/KeyboardNavigationTests_Tab.cs
-
tests/Avalonia.Base.UnitTests/Utilities/DelegateCommand.cs
|
|
|
@ -649,12 +649,12 @@ namespace Avalonia.Input.Navigation |
|
|
|
private static bool IsTabStop(IInputElement e) |
|
|
|
{ |
|
|
|
if (e is InputElement ie) |
|
|
|
return ie.Focusable && KeyboardNavigation.GetIsTabStop(ie) && ie.IsVisible && ie.IsEnabled; |
|
|
|
return ie.Focusable && KeyboardNavigation.GetIsTabStop(ie) && ie.IsVisible && ie.IsEffectivelyEnabled; |
|
|
|
return false; |
|
|
|
} |
|
|
|
|
|
|
|
private static bool IsTabStopOrGroup(IInputElement e) => IsTabStop(e) || IsGroup(e); |
|
|
|
private static bool IsVisible(IInputElement e) => (e as Visual)?.IsVisible ?? true; |
|
|
|
private static bool IsVisibleAndEnabled(IInputElement e) => IsVisible(e) && e.IsEnabled; |
|
|
|
private static bool IsVisibleAndEnabled(IInputElement e) => IsVisible(e) && e.IsEffectivelyEnabled; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
@ -1,6 +1,4 @@ |
|
|
|
using System; |
|
|
|
using System.Windows.Input; |
|
|
|
using Avalonia.Controls; |
|
|
|
using Avalonia.Controls; |
|
|
|
using Avalonia.Input; |
|
|
|
using Avalonia.Input.Raw; |
|
|
|
using Avalonia.UnitTests; |
|
|
|
@ -112,7 +110,7 @@ namespace Avalonia.Base.UnitTests.Input |
|
|
|
button.KeyBindings.Add(new KeyBinding |
|
|
|
{ |
|
|
|
Gesture = new KeyGesture(Key.O, KeyModifiers.Control), |
|
|
|
Command = new DelegateCommand(() => |
|
|
|
Command = new Utilities.DelegateCommand(() => |
|
|
|
{ |
|
|
|
button.KeyBindings.Clear(); |
|
|
|
++raised; |
|
|
|
@ -134,15 +132,6 @@ namespace Avalonia.Base.UnitTests.Input |
|
|
|
Assert.Equal(1, raised); |
|
|
|
} |
|
|
|
|
|
|
|
private class DelegateCommand : ICommand |
|
|
|
{ |
|
|
|
private readonly Action _action; |
|
|
|
public DelegateCommand(Action action) => _action = action; |
|
|
|
public event EventHandler CanExecuteChanged { add { } remove { } } |
|
|
|
public bool CanExecute(object parameter) => true; |
|
|
|
public void Execute(object parameter) => _action(); |
|
|
|
} |
|
|
|
|
|
|
|
[Fact] |
|
|
|
public void Control_Focus_Should_Be_Set_Before_FocusedElement_Raises_PropertyChanged() |
|
|
|
{ |
|
|
|
|
|
|
|
@ -1,3 +1,4 @@ |
|
|
|
using System; |
|
|
|
using System.Collections.Generic; |
|
|
|
using Avalonia.Controls; |
|
|
|
using Avalonia.Input; |
|
|
|
@ -1273,5 +1274,42 @@ namespace Avalonia.Base.UnitTests.Input |
|
|
|
|
|
|
|
Assert.True(button.IsFocused); |
|
|
|
} |
|
|
|
|
|
|
|
[Fact] |
|
|
|
public void Next_Skip_Button_When_Command_CanExecute_Is_False() |
|
|
|
{ |
|
|
|
Button current; |
|
|
|
Button expected; |
|
|
|
bool executed = false; |
|
|
|
|
|
|
|
var top = new StackPanel |
|
|
|
{ |
|
|
|
[KeyboardNavigation.TabNavigationProperty] = KeyboardNavigationMode.Cycle, |
|
|
|
Children = |
|
|
|
{ |
|
|
|
new StackPanel |
|
|
|
{ |
|
|
|
Children = |
|
|
|
{ |
|
|
|
(current = new Button { Name = "Button1" }), |
|
|
|
new Button |
|
|
|
{ |
|
|
|
Name = "Button2", |
|
|
|
Command = new Utilities.DelegateCommand(()=>executed = true, |
|
|
|
_ => false), |
|
|
|
}, |
|
|
|
(expected = new Button { Name = "Button3" }), |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
}; |
|
|
|
|
|
|
|
var result = KeyboardNavigationHandler.GetNext(current, NavigationDirection.Next) as Button; |
|
|
|
|
|
|
|
Assert.Equal(expected.Name, result?.Name); |
|
|
|
Assert.False(executed); |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
@ -0,0 +1,19 @@ |
|
|
|
using System; |
|
|
|
using System.Windows.Input; |
|
|
|
|
|
|
|
namespace Avalonia.Base.UnitTests.Utilities; |
|
|
|
|
|
|
|
internal class DelegateCommand : ICommand |
|
|
|
{ |
|
|
|
private readonly Action _action; |
|
|
|
private readonly Func<object, bool> _canExecute; |
|
|
|
public DelegateCommand(Action action, Func<object, bool> canExecute = default) |
|
|
|
{ |
|
|
|
_action = action; |
|
|
|
_canExecute = canExecute ?? new(_ => true); |
|
|
|
} |
|
|
|
|
|
|
|
public event EventHandler CanExecuteChanged { add { } remove { } } |
|
|
|
public bool CanExecute(object parameter) => _canExecute(parameter); |
|
|
|
public void Execute(object parameter) => _action(); |
|
|
|
} |