Browse Source

Improve KeyDown behavior in DropDown

CommonGuy 7 years ago
parent
commit
55da255d86
2 changed files with 76 additions and 39 deletions
  1. 42 38
      src/Avalonia.Controls/DropDown.cs
  2. 34 1
      src/Avalonia.Controls/DropDownItem.cs

+ 42 - 38
src/Avalonia.Controls/DropDown.cs

@@ -6,7 +6,6 @@ using Avalonia.Controls.Generators;
 using Avalonia.Controls.Primitives;
 using Avalonia.Controls.Shapes;
 using Avalonia.Input;
-using Avalonia.Layout;
 using Avalonia.LogicalTree;
 using Avalonia.Media;
 using Avalonia.VisualTree;
@@ -51,6 +50,7 @@ namespace Avalonia.Controls
         {
             FocusableProperty.OverrideDefaultValue<DropDown>(true);
             SelectedItemProperty.Changed.AddClassHandler<DropDown>(x => x.SelectedItemChanged);
+            KeyDownEvent.AddClassHandler<DropDown>(x => x.OnKeyDown, Interactivity.RoutingStrategies.Tunnel);
         }
 
         /// <summary>
@@ -96,54 +96,46 @@ namespace Avalonia.Controls
             this.UpdateSelectionBoxItem(this.SelectedItem);
         }
 
-        protected override void OnGotFocus(GotFocusEventArgs e)
-        {
-            base.OnGotFocus(e);
-
-            if (!e.Handled && e.NavigationMethod == NavigationMethod.Directional)
-            {
-                e.Handled = UpdateSelectionFromEventSource(e.Source);
-            }
-        }
-
         /// <inheritdoc/>
         protected override void OnKeyDown(KeyEventArgs e)
         {
             base.OnKeyDown(e);
 
-            if (!e.Handled)
+            if (e.Handled)
+                return;
+
+            if (e.Key == Key.F4 ||
+                ((e.Key == Key.Down || e.Key == Key.Up) && ((e.Modifiers & InputModifiers.Alt) != 0)))
             {
-                if (e.Key == Key.F4 ||
-                    ((e.Key == Key.Down || e.Key == Key.Up) && ((e.Modifiers & InputModifiers.Alt) != 0)))
+                IsDropDownOpen = !IsDropDownOpen;
+                e.Handled = true;
+            }
+            else if (IsDropDownOpen && e.Key == Key.Escape)
+            {
+                IsDropDownOpen = false;
+                e.Handled = true;
+            }
+            else if (IsDropDownOpen && e.Key == Key.Enter)
+            {
+                SelectFocusedItem();
+                IsDropDownOpen = false;
+                e.Handled = true;
+            }
+            else if (!IsDropDownOpen)
+            {
+                if (e.Key == Key.Down)
                 {
-                    IsDropDownOpen = !IsDropDownOpen;
+                    if (++SelectedIndex >= ItemCount)
+                        SelectedIndex = 0;
+
                     e.Handled = true;
                 }
-                else if (IsDropDownOpen && (e.Key == Key.Escape || e.Key == Key.Enter))
+                else if (e.Key == Key.Up)
                 {
-                    IsDropDownOpen = false;
-                    e.Handled = true;
-                }
+                    if (--SelectedIndex < 0)
+                        SelectedIndex = ItemCount - 1;
 
-                if (!IsDropDownOpen)
-                {
-                    if (e.Key == Key.Down)
-                    {
-                        if (SelectedIndex == -1)
-                            SelectedIndex = 0;
-                        
-                        if (++SelectedIndex >= ItemCount)
-                            SelectedIndex = 0;
-                        
-                        e.Handled = true;
-                    }
-                    else if (e.Key == Key.Up)
-                    {
-                        if (--SelectedIndex < 0)
-                            SelectedIndex = ItemCount - 1;
-                        
-                        e.Handled = true;
-                    }
+                    e.Handled = true;
                 }
             }
         }
@@ -230,5 +222,17 @@ namespace Avalonia.Controls
                 SelectionBoxItem = item;
             }
         }
+
+        private void SelectFocusedItem()
+        {
+            foreach (ItemContainerInfo dropdownItem in ItemContainerGenerator.Containers)
+            {
+                if (dropdownItem.ContainerControl.IsFocused)
+                {
+                    SelectedIndex = dropdownItem.Index;
+                    break;
+                }
+            }
+        }
     }
 }

+ 34 - 1
src/Avalonia.Controls/DropDownItem.cs

@@ -1,12 +1,45 @@
 // Copyright (c) The Avalonia Project. All rights reserved.
 // Licensed under the MIT license. See licence.md file in the project root for full license information.
 
+using System;
+
 namespace Avalonia.Controls
 {
     /// <summary>
     /// A selectable item in a <see cref="DropDown"/>.
     /// </summary>
-    public class DropDownItem : ListBoxItem
+    public class DropDownItem : ContentControl, ISelectable
     {
+        /// <summary>
+        /// Defines the <see cref="IsSelected"/> property.
+        /// </summary>
+        public static readonly StyledProperty<bool> IsSelectedProperty =
+            AvaloniaProperty.Register<DropDownItem, bool>(nameof(IsSelected));
+
+        /// <summary>
+        /// Initializes static members of the <see cref="DropDownItem"/> class.
+        /// </summary>
+        static DropDownItem()
+        {
+            FocusableProperty.OverrideDefaultValue<DropDownItem>(true);
+            IsFocusedProperty.Changed.Subscribe(x =>
+            {
+                var sender = x.Sender as IControl;
+
+                if (sender != null)
+                {
+                    ((IPseudoClasses)sender.Classes).Set(":selected", (bool)x.NewValue);
+                }
+            });
+        }
+
+        /// <summary>
+        /// Gets or sets the selection state of the item.
+        /// </summary>
+        public bool IsSelected
+        {
+            get { return GetValue(IsSelectedProperty); }
+            set { SetValue(IsSelectedProperty, value); }
+        }
     }
 }