From 5483071599cb0a3802c15389b8e893210b5f03b9 Mon Sep 17 00:00:00 2001 From: Max Katz Date: Sat, 12 Jun 2021 15:42:39 -0400 Subject: [PATCH] Fix cancellable contexts #6057 --- .../Pages/ContextFlyoutPage.xaml | 5 +-- .../ControlCatalog/Pages/ContextMenuPage.xaml | 7 ++-- src/Avalonia.Controls/ContextMenu.cs | 6 ++++ src/Avalonia.Controls/Flyouts/FlyoutBase.cs | 33 +++++++++++++++---- src/Avalonia.Controls/Primitives/Popup.cs | 10 ++++++ 5 files changed, 51 insertions(+), 10 deletions(-) diff --git a/samples/ControlCatalog/Pages/ContextFlyoutPage.xaml b/samples/ControlCatalog/Pages/ContextFlyoutPage.xaml index b54b3fbdbf..cc17d9c747 100644 --- a/samples/ControlCatalog/Pages/ContextFlyoutPage.xaml +++ b/samples/ControlCatalog/Pages/ContextFlyoutPage.xaml @@ -78,12 +78,13 @@ - + + + - diff --git a/samples/ControlCatalog/Pages/ContextMenuPage.xaml b/samples/ControlCatalog/Pages/ContextMenuPage.xaml index 801e4a6c20..7e564efafc 100644 --- a/samples/ControlCatalog/Pages/ContextMenuPage.xaml +++ b/samples/ControlCatalog/Pages/ContextMenuPage.xaml @@ -71,13 +71,16 @@ - + + + + + - diff --git a/src/Avalonia.Controls/ContextMenu.cs b/src/Avalonia.Controls/ContextMenu.cs index 57e4909e39..ca55fd0bc7 100644 --- a/src/Avalonia.Controls/ContextMenu.cs +++ b/src/Avalonia.Controls/ContextMenu.cs @@ -329,6 +329,7 @@ namespace Avalonia.Controls _popup.Opened += PopupOpened; _popup.Closed += PopupClosed; + _popup.Closing += PopupClosing; } if (_popup.Parent != control) @@ -355,6 +356,11 @@ namespace Avalonia.Controls Focus(); } + private void PopupClosing(object sender, CancelEventArgs e) + { + e.Cancel = CancelClosing(); + } + private void PopupClosed(object sender, EventArgs e) { foreach (var i in LogicalChildren) diff --git a/src/Avalonia.Controls/Flyouts/FlyoutBase.cs b/src/Avalonia.Controls/Flyouts/FlyoutBase.cs index e4b68c62fd..011af4e7a5 100644 --- a/src/Avalonia.Controls/Flyouts/FlyoutBase.cs +++ b/src/Avalonia.Controls/Flyouts/FlyoutBase.cs @@ -151,11 +151,7 @@ namespace Avalonia.Controls.Primitives if (canCancel) { - bool cancel = false; - - var closing = new CancelEventArgs(); - Closing?.Invoke(this, closing); - if (cancel || closing.Cancel) + if (CancelClosing()) { return; } @@ -195,6 +191,11 @@ namespace Avalonia.Controls.Primitives } } + if (CancelOpening()) + { + return; + } + if (Popup.Parent != null && Popup.Parent != placementTarget) { ((ISetLogicalParent)Popup).SetParent(null); @@ -328,6 +329,7 @@ namespace Avalonia.Controls.Primitives Popup.Opened += OnPopupOpened; Popup.Closed += OnPopupClosed; + Popup.Closing += OnPopupClosing; } private void OnPopupOpened(object sender, EventArgs e) @@ -335,9 +337,14 @@ namespace Avalonia.Controls.Primitives IsOpen = true; } + private void OnPopupClosing(object sender, CancelEventArgs e) + { + e.Cancel = CancelClosing(); + } + private void OnPopupClosed(object sender, EventArgs e) { - HideCore(); + HideCore(false); } private void PositionPopup(bool showAtPointer) @@ -483,6 +490,20 @@ namespace Avalonia.Controls.Primitives } } + private bool CancelClosing() + { + var eventArgs = new CancelEventArgs(); + Closing?.Invoke(this, eventArgs); + return eventArgs.Cancel; + } + + private bool CancelOpening() + { + var eventArgs = new CancelEventArgs(); + Opening?.Invoke(this, eventArgs); + return eventArgs.Cancel; + } + internal static void SetPresenterClasses(IControl presenter, Classes classes) { //Remove any classes no longer in use, ignoring pseudoclasses diff --git a/src/Avalonia.Controls/Primitives/Popup.cs b/src/Avalonia.Controls/Primitives/Popup.cs index b445de0472..f23a27e67a 100644 --- a/src/Avalonia.Controls/Primitives/Popup.cs +++ b/src/Avalonia.Controls/Primitives/Popup.cs @@ -1,4 +1,5 @@ using System; +using System.ComponentModel; using System.Linq; using System.Reactive.Disposables; using Avalonia.Controls.Presenters; @@ -154,6 +155,8 @@ namespace Avalonia.Controls.Primitives /// public event EventHandler? Opened; + internal event EventHandler? Closing; + public IPopupHost? Host => _openState?.PopupHost; public bool WindowManagerAddShadowHint @@ -567,6 +570,13 @@ namespace Avalonia.Controls.Primitives private void CloseCore() { + var closingArgs = new CancelEventArgs(); + Closing?.Invoke(this, closingArgs); + if (closingArgs.Cancel) + { + return; + } + _isOpenRequested = false; if (_openState is null) {