Browse Source

Allow context menus to be shared.

Either via resources or styles.
pull/3751/head
Steven Kirk 6 years ago
parent
commit
2048948541
  1. 39
      src/Avalonia.Controls/ContextMenu.cs

39
src/Avalonia.Controls/ContextMenu.cs

@ -1,4 +1,5 @@
using System; using System;
using System.Collections.Generic;
using System.ComponentModel; using System.ComponentModel;
using System.Linq; using System.Linq;
using Avalonia.Controls.Generators; using Avalonia.Controls.Generators;
@ -9,18 +10,19 @@ using Avalonia.Input;
using Avalonia.Interactivity; using Avalonia.Interactivity;
using Avalonia.Layout; using Avalonia.Layout;
using Avalonia.LogicalTree; using Avalonia.LogicalTree;
using Avalonia.Styling;
namespace Avalonia.Controls namespace Avalonia.Controls
{ {
/// <summary> /// <summary>
/// A control context menu. /// A control context menu.
/// </summary> /// </summary>
public class ContextMenu : MenuBase public class ContextMenu : MenuBase, ISetterValue
{ {
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 Control _attachedControl; private List<Control> _attachedControls;
private IInputElement _previousFocus; private IInputElement _previousFocus;
/// <summary> /// <summary>
@ -74,13 +76,14 @@ namespace Avalonia.Controls
if (e.OldValue is ContextMenu oldMenu) if (e.OldValue is ContextMenu oldMenu)
{ {
control.PointerReleased -= ControlPointerReleased; control.PointerReleased -= ControlPointerReleased;
oldMenu._attachedControl = null; oldMenu._attachedControls?.Remove(control);
((ISetLogicalParent)oldMenu._popup)?.SetParent(null); ((ISetLogicalParent)oldMenu._popup)?.SetParent(null);
} }
if (e.NewValue is ContextMenu newMenu) if (e.NewValue is ContextMenu newMenu)
{ {
newMenu._attachedControl = control; newMenu._attachedControls ??= new List<Control>();
newMenu._attachedControls.Add(control);
control.PointerReleased += ControlPointerReleased; control.PointerReleased += ControlPointerReleased;
} }
} }
@ -96,18 +99,22 @@ namespace Avalonia.Controls
/// <param name="control">The control.</param> /// <param name="control">The control.</param>
public void Open(Control 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)); 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( throw new ArgumentException(
"Cannot show ContentMenu on a different control to the one it is attached to.", "Cannot show ContentMenu on a different control to the one it is attached to.",
nameof(control)); nameof(control));
} }
control ??= _attachedControls[0];
if (IsOpen) if (IsOpen)
{ {
return; return;
@ -126,7 +133,12 @@ namespace Avalonia.Controls
_popup.Closed += PopupClosed; _popup.Closed += PopupClosed;
} }
((ISetLogicalParent)_popup).SetParent(control); if (_popup.Parent != control)
{
((ISetLogicalParent)_popup).SetParent(null);
((ISetLogicalParent)_popup).SetParent(control);
}
_popup.Child = this; _popup.Child = this;
_popup.IsOpen = true; _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 <template>.
if (!(setter is Setter s && s.Property == ContextMenuProperty))
{
throw new InvalidOperationException(
"Cannot use a control as a Setter value. Wrap the control in a <Template>.");
}
}
protected override IItemContainerGenerator CreateItemContainerGenerator() protected override IItemContainerGenerator CreateItemContainerGenerator()
{ {
return new MenuItemContainerGenerator(this); return new MenuItemContainerGenerator(this);
@ -179,7 +202,7 @@ namespace Avalonia.Controls
SelectedIndex = -1; SelectedIndex = -1;
IsOpen = false; IsOpen = false;
if (_attachedControl is null) if (_attachedControls is null || _attachedControls.Count == 0)
{ {
((ISetLogicalParent)_popup).SetParent(null); ((ISetLogicalParent)_popup).SetParent(null);
} }

Loading…
Cancel
Save