From 204894854120d9b3fa898906ffd74202ccc7a05a Mon Sep 17 00:00:00 2001 From: Steven Kirk Date: Mon, 6 Apr 2020 22:48:25 +0200 Subject: [PATCH] Allow context menus to be shared. Either via resources or styles. --- src/Avalonia.Controls/ContextMenu.cs | 39 ++++++++++++++++++++++------ 1 file changed, 31 insertions(+), 8 deletions(-) diff --git a/src/Avalonia.Controls/ContextMenu.cs b/src/Avalonia.Controls/ContextMenu.cs index 1735599988..86499530da 100644 --- a/src/Avalonia.Controls/ContextMenu.cs +++ b/src/Avalonia.Controls/ContextMenu.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using System.ComponentModel; using System.Linq; using Avalonia.Controls.Generators; @@ -9,18 +10,19 @@ using Avalonia.Input; using Avalonia.Interactivity; using Avalonia.Layout; using Avalonia.LogicalTree; +using Avalonia.Styling; namespace Avalonia.Controls { /// /// A control context menu. /// - public class ContextMenu : MenuBase + public class ContextMenu : MenuBase, ISetterValue { private static readonly ITemplate DefaultPanel = new FuncTemplate(() => new StackPanel { Orientation = Orientation.Vertical }); private Popup _popup; - private Control _attachedControl; + private List _attachedControls; private IInputElement _previousFocus; /// @@ -74,13 +76,14 @@ namespace Avalonia.Controls if (e.OldValue is ContextMenu oldMenu) { control.PointerReleased -= ControlPointerReleased; - oldMenu._attachedControl = null; + oldMenu._attachedControls?.Remove(control); ((ISetLogicalParent)oldMenu._popup)?.SetParent(null); } if (e.NewValue is ContextMenu newMenu) { - newMenu._attachedControl = control; + newMenu._attachedControls ??= new List(); + newMenu._attachedControls.Add(control); control.PointerReleased += ControlPointerReleased; } } @@ -96,18 +99,22 @@ namespace Avalonia.Controls /// The control. public void Open(Control control) { - if (control is null && _attachedControl is null) + if (control is null && (_attachedControls is null || _attachedControls.Count == 0)) { throw new ArgumentNullException(nameof(control)); } - if (control is object && _attachedControl is object && control != _attachedControl) + if (control is object && + _attachedControls is object && + !_attachedControls.Contains(control)) { throw new ArgumentException( "Cannot show ContentMenu on a different control to the one it is attached to.", nameof(control)); } + control ??= _attachedControls[0]; + if (IsOpen) { return; @@ -126,7 +133,12 @@ namespace Avalonia.Controls _popup.Closed += PopupClosed; } - ((ISetLogicalParent)_popup).SetParent(control); + if (_popup.Parent != control) + { + ((ISetLogicalParent)_popup).SetParent(null); + ((ISetLogicalParent)_popup).SetParent(control); + } + _popup.Child = this; _popup.IsOpen = true; @@ -155,6 +167,17 @@ namespace Avalonia.Controls } } + void ISetterValue.Initialize(ISetter setter) + { + // ContextMenu can be assigned to the ContextMenu property in a setter. This overrides + // the behavior defined in Control which requires controls to be wrapped in a