8 changed files with 221 additions and 7 deletions
@ -0,0 +1,149 @@ |
|||
namespace Perspex.Controls |
|||
{ |
|||
using Input; |
|||
using Interactivity; |
|||
using LogicalTree; |
|||
using Primitives; |
|||
using System; |
|||
using System.Reactive.Linq; |
|||
|
|||
public class ContextMenu : SelectingItemsControl |
|||
{ |
|||
private bool _isOpen; |
|||
|
|||
/// <summary>
|
|||
/// The popup window used to display the active context menu.
|
|||
/// </summary>
|
|||
private static Popup _popup; |
|||
|
|||
/// <summary>
|
|||
/// Initializes static members of the <see cref="ContextMenu"/> class.
|
|||
/// </summary>
|
|||
static ContextMenu() |
|||
{ |
|||
ContextMenuProperty.Changed.Subscribe(ContextMenuChanged); |
|||
|
|||
MenuItem.ClickEvent.AddClassHandler<ContextMenu>(x => x.OnContextMenuClick); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// called when the <see cref="ContextMenuProperty"/> property changes on a control.
|
|||
/// </summary>
|
|||
/// <param name="e">The event args.</param>
|
|||
private static void ContextMenuChanged(PerspexPropertyChangedEventArgs e) |
|||
{ |
|||
var control = (Control)e.Sender; |
|||
|
|||
if (e.OldValue != null) |
|||
{ |
|||
control.PointerReleased -= ControlPointerReleased; |
|||
} |
|||
|
|||
if (e.NewValue != null) |
|||
{ |
|||
control.PointerReleased += ControlPointerReleased; |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Called when a submenu is clicked somewhere in the menu.
|
|||
/// </summary>
|
|||
/// <param name="e">The event args.</param>
|
|||
private void OnContextMenuClick(RoutedEventArgs e) |
|||
{ |
|||
Hide(); |
|||
FocusManager.Instance.Focus(null); |
|||
e.Handled = true; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Closes the menu.
|
|||
/// </summary>
|
|||
public void Hide() |
|||
{ |
|||
|
|||
|
|||
if (_popup != null && _popup.IsVisible) |
|||
{ |
|||
_popup.Close(); |
|||
} |
|||
|
|||
SelectedIndex = -1; |
|||
|
|||
_isOpen = false; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Shows a context menu for the specified control.
|
|||
/// </summary>
|
|||
/// <param name="control">The control.</param>
|
|||
private static void Show(Control control) |
|||
{ |
|||
if (control != null) |
|||
{ |
|||
if(_popup == null) |
|||
{ |
|||
_popup = new Popup() |
|||
{ |
|||
PlacementTarget = control, |
|||
StaysOpen = false |
|||
}; |
|||
|
|||
_popup.Closed += PopupClosed; |
|||
} |
|||
|
|||
((ISetLogicalParent)_popup).SetParent(control); |
|||
_popup.Child = control.ContextMenu; |
|||
|
|||
_popup.Open(); |
|||
|
|||
control.ContextMenu._isOpen = true; |
|||
} |
|||
} |
|||
|
|||
private static void PopupClosed(object sender, EventArgs e) |
|||
{ |
|||
var contextMenu = (sender as Popup)?.Child as ContextMenu; |
|||
|
|||
if (contextMenu != null) |
|||
{ |
|||
foreach (MenuItem i in contextMenu.GetLogicalChildren()) |
|||
{ |
|||
i.IsSubMenuOpen = false; |
|||
} |
|||
|
|||
contextMenu._isOpen = false; |
|||
} |
|||
} |
|||
|
|||
private void PopupOpened(object sender, EventArgs e) |
|||
{ |
|||
var selectedIndex = SelectedIndex; |
|||
|
|||
if (selectedIndex != -1) |
|||
{ |
|||
var container = ItemContainerGenerator.ContainerFromIndex(selectedIndex); |
|||
container?.Focus(); |
|||
} |
|||
} |
|||
|
|||
private static void ControlPointerReleased(object sender, PointerReleasedEventArgs e) |
|||
{ |
|||
var control = (Control)sender; |
|||
|
|||
if (e.MouseButton == MouseButton.Right) |
|||
{ |
|||
if (control.ContextMenu._isOpen) |
|||
{ |
|||
control.ContextMenu.Hide(); |
|||
} |
|||
|
|||
Show(control); |
|||
} |
|||
else |
|||
{ |
|||
control.ContextMenu.Hide(); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,20 @@ |
|||
<Style xmlns="https://github.com/perspex" Selector="ContextMenu"> |
|||
<Setter Property="BorderBrush" Value="Gray"/> |
|||
<Setter Property="BorderThickness" Value="1"/> |
|||
<Setter Property="Padding" Value="4,2"/> |
|||
<Setter Property="FontSize" Value="12" /> |
|||
<Setter Property="FontWeight" Value="Normal" /> |
|||
<Setter Property="Template"> |
|||
<ControlTemplate> |
|||
<Border Background="{TemplateBinding Background}" |
|||
BorderBrush="{TemplateBinding BorderBrush}" |
|||
BorderThickness="{TemplateBinding BorderThickness}" |
|||
Padding="{TemplateBinding Padding}"> |
|||
<ItemsPresenter Name="PART_ItemsPresenter" |
|||
Items="{TemplateBinding Items}" |
|||
ItemsPanel="{TemplateBinding ItemsPanel}" |
|||
KeyboardNavigation.TabNavigation="Continue"/> |
|||
</Border> |
|||
</ControlTemplate> |
|||
</Setter> |
|||
</Style> |
|||
Loading…
Reference in new issue