From f32f293f3074dde9cd2d4f550d4deec5b9f3b25b Mon Sep 17 00:00:00 2001 From: danwalmsley Date: Thu, 4 Feb 2016 15:22:41 +0000 Subject: [PATCH] Added implementation of ContextMenus. --- .../Views/MainWindow.paml | 16 +- src/Perspex.Controls/ContextMenu.cs | 154 +++++++++++++++++- src/Perspex.Controls/Control.cs | 16 ++ src/Perspex.Themes.Default/ContextMenu.paml | 4 +- 4 files changed, 180 insertions(+), 10 deletions(-) diff --git a/samples/XamlTestApplicationPcl/Views/MainWindow.paml b/samples/XamlTestApplicationPcl/Views/MainWindow.paml index 169e9eb6a2..d846a26821 100644 --- a/samples/XamlTestApplicationPcl/Views/MainWindow.paml +++ b/samples/XamlTestApplicationPcl/Views/MainWindow.paml @@ -38,8 +38,20 @@ - - + + + + + + + + + + + + + + MenuProperty = - PerspexProperty.RegisterAttached("Menu"); + private bool _isOpen; - public static ContextMenu GetMenu(TextBlock element) + /// + /// Defines the ContextMenu.Menu attached property. + /// + //public static readonly AttachedProperty ContextMenuProperty = + // PerspexProperty.RegisterAttached("Menu"); + + /// + /// The popup window used to display the active context menu. + /// + private static PopupRoot s_popup; + + /// + /// The control that the currently visible context menu is attached to. + /// + private static Control s_current; + + /// + /// Initializes static members of the class. + /// + static ContextMenu() + { + ContextMenuProperty.Changed.Subscribe(ContextMenuChanged); + + MenuItem.ClickEvent.AddClassHandler(x => x.OnContextMenuClick); + } + + /// + /// Gets the value of the ToolTip.Tip attached property. + /// + /// The control to get the property from. + /// + /// The content to be displayed in the control's tooltip. + /// + public static object GetContextMenu(Control element) + { + return element.GetValue(ContextMenuProperty); + } + + /// + /// Sets the value of the ToolTip.Tip attached property. + /// + /// The control to get the property from. + /// The content to be displayed in the control's tooltip. + public static void SetContextMenu(Control element, object value) + { + element.SetValue(ContextMenuProperty, value); + } + + /// + /// called when the property changes on a control. + /// + /// The event args. + 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; + } + } + + /// + /// Called when a submenu is clicked somewhere in the menu. + /// + /// The event args. + private void OnContextMenuClick(RoutedEventArgs e) { - return element.GetValue(MenuProperty); + Hide(); + FocusManager.Instance.Focus(null); + e.Handled = true; } - public static void SetMenu(TextBlock element, ContextMenu value) + /// + /// Closes the menu. + /// + public void Hide() { - element.SetValue(MenuProperty, value); + foreach (MenuItem i in this.GetLogicalChildren()) + { + i.IsSubMenuOpen = false; + } + + if (s_popup != null && s_popup.IsVisible) + { + s_popup.Hide(); + } + + SelectedIndex = -1; + + _isOpen = false; + } + + /// + /// Shows a tooltip for the specified control. + /// + /// The control. + private static void Show(Control control) + { + if (control != null) + { + if (s_popup == null) + { + s_popup = new PopupRoot + { + Content = new ToolTip(), + }; + + ((ISetLogicalParent)s_popup).SetParent(control); + } + + var cp = MouseDevice.Instance?.GetPosition(control); + var position = control.PointToScreen(cp ?? new Point(0, 0)); + + ((ToolTip)s_popup.Content).Content = GetContextMenu(control); + s_popup.Position = position; + s_popup.Show(); + + s_current = control; + + control.ContextMenu._isOpen = true; + } + } + + 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(); + } } } } diff --git a/src/Perspex.Controls/Control.cs b/src/Perspex.Controls/Control.cs index 3a14987c50..74d67e0f4a 100644 --- a/src/Perspex.Controls/Control.cs +++ b/src/Perspex.Controls/Control.cs @@ -65,6 +65,13 @@ namespace Perspex.Controls public static readonly StyledProperty TemplatedParentProperty = PerspexProperty.Register(nameof(TemplatedParent), inherits: true); + /// + /// Defines the property. + /// + public static readonly StyledProperty ContextMenuProperty = + PerspexProperty.Register(nameof(ContextMenu)); + + /// /// Event raised when an element wishes to be scrolled into view. /// @@ -204,6 +211,15 @@ namespace Perspex.Controls /// public IControl Parent => _parent; + /// + /// Gets or sets a context menu to the control. + /// + public ContextMenu ContextMenu + { + get { return GetValue(ContextMenuProperty); } + set { SetValue(ContextMenuProperty, value); } + } + /// /// Gets or sets a user-defined object attached to the control. /// diff --git a/src/Perspex.Themes.Default/ContextMenu.paml b/src/Perspex.Themes.Default/ContextMenu.paml index 0665a58531..e00ec6ddef 100644 --- a/src/Perspex.Themes.Default/ContextMenu.paml +++ b/src/Perspex.Themes.Default/ContextMenu.paml @@ -5,8 +5,8 @@ BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Padding="{TemplateBinding Padding}"> -