Browse Source

Remove ContextMenu from logical tree.

When the `ContextMenu` is not attached to a control, i.e. it is shown using `Show(control)` then we need to detach it from the logical tree once hidden otherwise it will leak, causing #3738.
pull/3745/head
Steven Kirk 7 years ago
parent
commit
76b4d17abf
  1. 41
      src/Avalonia.Controls/ContextMenu.cs

41
src/Avalonia.Controls/ContextMenu.cs

@ -20,6 +20,7 @@ namespace Avalonia.Controls
private static readonly ITemplate<IPanel> DefaultPanel = private static readonly ITemplate<IPanel> DefaultPanel =
new FuncTemplate<IPanel>(() => new StackPanel { Orientation = Orientation.Vertical }); new FuncTemplate<IPanel>(() => new StackPanel { Orientation = Orientation.Vertical });
private Popup _popup; private Popup _popup;
private bool _attachedToControl;
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="ContextMenu"/> class. /// Initializes a new instance of the <see cref="ContextMenu"/> class.
@ -69,13 +70,15 @@ namespace Avalonia.Controls
{ {
var control = (Control)e.Sender; var control = (Control)e.Sender;
if (e.OldValue != null) if (e.OldValue is ContextMenu oldMenu)
{ {
control.PointerReleased -= ControlPointerReleased; control.PointerReleased -= ControlPointerReleased;
oldMenu._attachedToControl = false;
} }
if (e.NewValue != null) if (e.NewValue is ContextMenu newMenu)
{ {
newMenu._attachedToControl = true;
control.PointerReleased += ControlPointerReleased; control.PointerReleased += ControlPointerReleased;
} }
} }
@ -145,18 +148,6 @@ namespace Avalonia.Controls
return new MenuItemContainerGenerator(this); return new MenuItemContainerGenerator(this);
} }
private void CloseCore()
{
SelectedIndex = -1;
IsOpen = false;
RaiseEvent(new RoutedEventArgs
{
RoutedEvent = MenuClosedEvent,
Source = this,
});
}
private void PopupOpened(object sender, EventArgs e) private void PopupOpened(object sender, EventArgs e)
{ {
Focus(); Focus();
@ -164,17 +155,27 @@ namespace Avalonia.Controls
private void PopupClosed(object sender, EventArgs e) private void PopupClosed(object sender, EventArgs e)
{ {
var contextMenu = (sender as Popup)?.Child as ContextMenu; foreach (var i in LogicalChildren)
if (contextMenu != null)
{ {
foreach (var i in contextMenu.GetLogicalChildren().OfType<MenuItem>()) if (i is MenuItem menuItem)
{ {
i.IsSubMenuOpen = false; menuItem.IsSubMenuOpen = false;
} }
}
SelectedIndex = -1;
IsOpen = false;
contextMenu.CloseCore(); if (!_attachedToControl)
{
((ISetLogicalParent)_popup).SetParent(null);
} }
RaiseEvent(new RoutedEventArgs
{
RoutedEvent = MenuClosedEvent,
Source = this,
});
} }
private static void ControlPointerReleased(object sender, PointerReleasedEventArgs e) private static void ControlPointerReleased(object sender, PointerReleasedEventArgs e)

Loading…
Cancel
Save