using System;
using System.Reactive.Linq;
using System.Linq;
using System.ComponentModel;
using Avalonia.Controls.Platform;
using System.Collections.Generic;
using Avalonia.Input;
using Avalonia.LogicalTree;
using Avalonia.Controls.Primitives;
namespace Avalonia.Controls
{
public class ContextMenu : SelectingItemsControl, IMenu
{
private readonly IMenuInteractionHandler _interaction;
private bool _isOpen;
private Popup _popup;
///
/// Defines the property.
///
public static readonly DirectProperty IsOpenProperty =
AvaloniaProperty.RegisterDirect(nameof(IsOpen), o => o.IsOpen);
///
/// Initializes a new instance of the class.
///
public ContextMenu()
{
_interaction = AvaloniaLocator.Current.GetService() ??
new DefaultMenuInteractionHandler();
}
///
/// Initializes a new instance of the class.
///
/// The menu iteraction handler.
public ContextMenu(IMenuInteractionHandler interactionHandler)
{
Contract.Requires(interactionHandler != null);
_interaction = interactionHandler;
}
///
/// Initializes static members of the class.
///
static ContextMenu()
{
ContextMenuProperty.Changed.Subscribe(ContextMenuChanged);
}
///
/// Gets a value indicating whether the popup is open
///
public bool IsOpen => _isOpen;
///
IMenuInteractionHandler IMenu.InteractionHandler => _interaction;
///
IMenuItem IMenuElement.SelectedItem
{
get
{
var index = SelectedIndex;
return (index != -1) ?
(IMenuItem)ItemContainerGenerator.ContainerFromIndex(index) :
null;
}
set
{
SelectedIndex = ItemContainerGenerator.IndexFromContainer(value);
}
}
///
IEnumerable IMenuElement.SubItems
{
get
{
return ItemContainerGenerator.Containers
.Select(x => x.ContainerControl)
.OfType();
}
}
///
/// 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.
///
/// The event args.
private static void ContextMenuChanged(AvaloniaPropertyChangedEventArgs e)
{
var control = (Control)e.Sender;
if (e.OldValue != null)
{
control.PointerReleased -= ControlPointerReleased;
}
if (e.NewValue != null)
{
control.PointerReleased += ControlPointerReleased;
}
}
///
/// Opens the menu.
///
public void Open() => Open(null);
///
/// Opens a context menu on the specified control.
///
/// The control.
public void Open(Control control)
{
if (_popup == null)
{
_popup = new Popup()
{
PlacementMode = PlacementMode.Pointer,
PlacementTarget = control,
StaysOpen = false,
ObeyScreenEdges = true
};
_popup.Closed += PopupClosed;
_interaction.Attach(this);
}
((ISetLogicalParent)_popup).SetParent(control);
_popup.Child = this;
_popup.IsOpen = true;
SetAndRaise(IsOpenProperty, ref _isOpen, true);
}
///
/// Closes the menu.
///
public void Close()
{
if (_popup != null && _popup.IsVisible)
{
_popup.IsOpen = false;
}
SelectedIndex = -1;
SetAndRaise(IsOpenProperty, ref _isOpen, false);
}
private void PopupClosed(object sender, EventArgs e)
{
var contextMenu = (sender as Popup)?.Child as ContextMenu;
if (contextMenu != null)
{
foreach (var i in contextMenu.GetLogicalChildren().OfType