Browse Source

fix: Navigation when CanExecute is fasle (#13507)

* test: Add test navigation with CanExecute is False

* fix: Navigation when CanExecute is false
workgroupengineering 2 years ago
parent
commit
99737a8395

+ 2 - 2
src/Avalonia.Base/Input/Navigation/TabNavigation.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;
     }
 }

+ 2 - 13
tests/Avalonia.Base.UnitTests/Input/KeyboardDeviceTests.cs

@@ -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()
         {

+ 38 - 0
tests/Avalonia.Base.UnitTests/Input/KeyboardNavigationTests_Tab.cs

@@ -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);
+        }
+
+
     }
 }

+ 19 - 0
tests/Avalonia.Base.UnitTests/Utilities/DelegateCommand.cs

@@ -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();
+}