diff --git a/src/Avalonia.Controls/ContextMenu.cs b/src/Avalonia.Controls/ContextMenu.cs index 78dc994df7..13f00bdc87 100644 --- a/src/Avalonia.Controls/ContextMenu.cs +++ b/src/Avalonia.Controls/ContextMenu.cs @@ -7,11 +7,20 @@ namespace Avalonia.Controls using System; using System.Reactive.Linq; using System.Linq; + using System.ComponentModel; + public class ContextMenu : SelectingItemsControl { private bool _isOpen; private Popup _popup; + /// + /// Defines the property. + /// + public static readonly DirectProperty IsOpenProperty = + AvaloniaProperty.RegisterDirect(nameof(IsOpen), o => o.IsOpen); + + /// /// Initializes static members of the class. /// @@ -22,6 +31,26 @@ namespace Avalonia.Controls MenuItem.ClickEvent.AddClassHandler(x => x.OnContextMenuClick, handledEventsToo: true); } + /// + /// Gets a value indicating whether the popup is open + /// + public bool IsOpen => _isOpen; + + /// + /// Occurs when the value of the + /// + /// property is changing from false to true. + /// + public event CancelEventHandler ContextMenuOpening; + + /// + /// Occurs when the value of the + /// + /// property is changing from true to false. + /// + public event CancelEventHandler ContextMenuClosing; + + /// /// Called when the property changes on a control. /// @@ -59,12 +88,12 @@ namespace Avalonia.Controls { if (_popup != null && _popup.IsVisible) { - _popup.Close(); + _popup.IsOpen = false; } SelectedIndex = -1; - _isOpen = false; + SetAndRaise(IsOpenProperty, ref _isOpen, false); } /// @@ -89,11 +118,11 @@ namespace Avalonia.Controls } ((ISetLogicalParent)_popup).SetParent(control); - _popup.Child = control.ContextMenu; + _popup.Child = this; - _popup.Open(); + _popup.IsOpen = true; - control.ContextMenu._isOpen = true; + SetAndRaise(IsOpenProperty, ref _isOpen, true); } } @@ -118,21 +147,37 @@ namespace Avalonia.Controls var control = (Control)sender; var contextMenu = control.ContextMenu; - if (e.MouseButton == MouseButton.Right) + if (control.ContextMenu._isOpen) { - if (control.ContextMenu._isOpen) - { - control.ContextMenu.Hide(); - } + if (contextMenu.CancelClosing()) + return; - contextMenu.Show(control); + control.ContextMenu.Hide(); e.Handled = true; } - else if (contextMenu._isOpen) + + if (e.MouseButton == MouseButton.Right) { - control.ContextMenu.Hide(); + if (contextMenu.CancelOpening()) + return; + + contextMenu.Show(control); e.Handled = true; } } + + private bool CancelClosing() + { + var eventArgs = new CancelEventArgs(); + ContextMenuClosing?.Invoke(this, eventArgs); + return eventArgs.Cancel; + } + + private bool CancelOpening() + { + var eventArgs = new CancelEventArgs(); + ContextMenuOpening?.Invoke(this, eventArgs); + return eventArgs.Cancel; + } } } diff --git a/src/Avalonia.Controls/Primitives/ToggleButton.cs b/src/Avalonia.Controls/Primitives/ToggleButton.cs index dc9b70ab8c..1d2e2f2100 100644 --- a/src/Avalonia.Controls/Primitives/ToggleButton.cs +++ b/src/Avalonia.Controls/Primitives/ToggleButton.cs @@ -14,7 +14,7 @@ namespace Avalonia.Controls.Primitives nameof(IsChecked), o => o.IsChecked, (o, v) => o.IsChecked = v, - unsetValue: false, + unsetValue: null, defaultBindingMode: BindingMode.TwoWay); public static readonly StyledProperty IsThreeStateProperty = diff --git a/src/Avalonia.Themes.Default/MenuItem.xaml b/src/Avalonia.Themes.Default/MenuItem.xaml index 47b4528f88..53965db016 100644 --- a/src/Avalonia.Themes.Default/MenuItem.xaml +++ b/src/Avalonia.Themes.Default/MenuItem.xaml @@ -122,6 +122,11 @@ + +