diff --git a/src/Avalonia.Controls/ContextMenu.cs b/src/Avalonia.Controls/ContextMenu.cs index 13f00bdc87..0accb284b6 100644 --- a/src/Avalonia.Controls/ContextMenu.cs +++ b/src/Avalonia.Controls/ContextMenu.cs @@ -1,16 +1,18 @@ +using System; +using System.Reactive.Linq; +using System.Linq; +using System.ComponentModel; +using Avalonia.Controls.Platform; +using System.Collections.Generic; +using Avalonia.Input; +using Avalonia.LogicalTree; +using Avalonia.Controls.Primitives; + namespace Avalonia.Controls { - using Input; - using Interactivity; - using LogicalTree; - using Primitives; - using System; - using System.Reactive.Linq; - using System.Linq; - using System.ComponentModel; - - public class ContextMenu : SelectingItemsControl + public class ContextMenu : SelectingItemsControl, IMenu { + private readonly IMenuInteractionHandler _interaction; private bool _isOpen; private Popup _popup; @@ -20,6 +22,25 @@ namespace Avalonia.Controls public static readonly DirectProperty IsOpenProperty = AvaloniaProperty.RegisterDirect(nameof(IsOpen), o => o.IsOpen); + /// + /// Initializes a new instance of the class. + /// + public ContextMenu() + { + _interaction = AvaloniaLocator.Current.GetService() ?? + new DefaultMenuInteractionHandler(); + } + + /// + /// Initializes a new instance of the class. + /// + /// The menu iteraction handler. + public ContextMenu(IMenuInteractionHandler interactionHandler) + { + Contract.Requires(interactionHandler != null); + + _interaction = interactionHandler; + } /// /// Initializes static members of the class. @@ -27,8 +48,6 @@ namespace Avalonia.Controls static ContextMenu() { ContextMenuProperty.Changed.Subscribe(ContextMenuChanged); - - MenuItem.ClickEvent.AddClassHandler(x => x.OnContextMenuClick, handledEventsToo: true); } /// @@ -36,6 +55,36 @@ namespace Avalonia.Controls /// public bool IsOpen => _isOpen; + /// + IMenuInteractionHandler IMenu.InteractionHandler => _interaction; + + /// + IMenuItem IMenuElement.SelectedItem + { + get + { + var index = SelectedIndex; + return (index != -1) ? + (IMenuItem)ItemContainerGenerator.ContainerFromIndex(index) : + null; + } + set + { + SelectedIndex = ItemContainerGenerator.IndexFromContainer(value); + } + } + + /// + IEnumerable IMenuElement.SubItems + { + get + { + return ItemContainerGenerator.Containers + .Select(x => x.ContainerControl) + .OfType(); + } + } + /// /// Occurs when the value of the /// @@ -50,7 +99,6 @@ namespace Avalonia.Controls /// public event CancelEventHandler ContextMenuClosing; - /// /// Called when the property changes on a control. /// @@ -71,62 +119,53 @@ namespace Avalonia.Controls } /// - /// Called when a submenu is clicked somewhere in the menu. + /// Opens the menu. /// - /// The event args. - private void OnContextMenuClick(RoutedEventArgs e) - { - Hide(); - FocusManager.Instance.Focus(null); - e.Handled = true; - } + public void Open() => Open(null); /// - /// Closes the menu. + /// Opens a context menu on the specified control. /// - public void Hide() + /// The control. + public void Open(Control control) { - if (_popup != null && _popup.IsVisible) + if (_popup == null) { - _popup.IsOpen = false; + _popup = new Popup() + { + PlacementMode = PlacementMode.Pointer, + PlacementTarget = control, + StaysOpen = false, + ObeyScreenEdges = true + }; + + _popup.Closed += PopupClosed; + _interaction.Attach(this); } - SelectedIndex = -1; + ((ISetLogicalParent)_popup).SetParent(control); + _popup.Child = this; + _popup.IsOpen = true; - SetAndRaise(IsOpenProperty, ref _isOpen, false); + SetAndRaise(IsOpenProperty, ref _isOpen, true); } /// - /// Shows a context menu for the specified control. + /// Closes the menu. /// - /// The control. - private void Show(Control control) + public void Close() { - if (control != null) + if (_popup != null && _popup.IsVisible) { - if (_popup == null) - { - _popup = new Popup() - { - PlacementMode = PlacementMode.Pointer, - PlacementTarget = control, - StaysOpen = false, - ObeyScreenEdges = true - }; - - _popup.Closed += PopupClosed; - } - - ((ISetLogicalParent)_popup).SetParent(control); - _popup.Child = this; + _popup.IsOpen = false; + } - _popup.IsOpen = true; + SelectedIndex = -1; - SetAndRaise(IsOpenProperty, ref _isOpen, true); - } + SetAndRaise(IsOpenProperty, ref _isOpen, false); } - private static void PopupClosed(object sender, EventArgs e) + private void PopupClosed(object sender, EventArgs e) { var contextMenu = (sender as Popup)?.Child as ContextMenu; @@ -152,7 +191,7 @@ namespace Avalonia.Controls if (contextMenu.CancelClosing()) return; - control.ContextMenu.Hide(); + control.ContextMenu.Close(); e.Handled = true; } @@ -161,7 +200,7 @@ namespace Avalonia.Controls if (contextMenu.CancelOpening()) return; - contextMenu.Show(control); + contextMenu.Open(control); e.Handled = true; } } @@ -179,5 +218,10 @@ namespace Avalonia.Controls ContextMenuOpening?.Invoke(this, eventArgs); return eventArgs.Cancel; } + + bool IMenuElement.MoveSelection(NavigationDirection direction, bool wrap) + { + throw new NotImplementedException(); + } } }