ContextMenu.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ 4.0 / 4.0 / untmp / DEVDIV_TFS / Dev10 / Releases / RTMRel / wpf / src / Framework / System / Windows / Controls / ContextMenu.cs / 1305600 / ContextMenu.cs

                            //---------------------------------------------------------------------------- 
//
// Copyright (C) Microsoft Corporation.  All rights reserved.
//
//--------------------------------------------------------------------------- 

using System; 
using MS.Internal; 
using MS.Internal.KnownBoxes;
using MS.Utility; 
using System.ComponentModel;
using System.Diagnostics;
using System.Windows.Threading;
using System.Windows; 
#if OLD_AUTOMATION
using System.Windows.Automation.Provider; 
#endif 
using System.Windows.Input;
using System.Windows.Media; 
using System.Windows.Controls.Primitives;
using System.Windows.Markup;
using System.Windows.Shapes;
using System.Security.Permissions; 

namespace System.Windows.Controls 
{ 
    /// 
    ///     Control that defines a menu of choices for users to invoke. 
    /// 
    [DefaultEvent("Opened")]
#if OLD_AUTOMATION
    [Automation(AccessibilityControlType = "Menu")] 
#endif
    public class ContextMenu : MenuBase 
    { 

        #region Constructors 

        //-------------------------------------------------------------------
        //
        //  Constructors 
        //
        //------------------------------------------------------------------- 
 
        static ContextMenu()
        { 

            EventManager.RegisterClassHandler(typeof(ContextMenu), AccessKeyManager.AccessKeyPressedEvent, new AccessKeyPressedEventHandler(OnAccessKeyPressed));

            DefaultStyleKeyProperty.OverrideMetadata(typeof(ContextMenu), new FrameworkPropertyMetadata(typeof(ContextMenu))); 
            _dType = DependencyObjectType.FromSystemTypeInternal(typeof(ContextMenu));
 
            IsTabStopProperty.OverrideMetadata(typeof(ContextMenu), new FrameworkPropertyMetadata(BooleanBoxes.FalseBox)); 
            KeyboardNavigation.TabNavigationProperty.OverrideMetadata(typeof(ContextMenu), new FrameworkPropertyMetadata(KeyboardNavigationMode.Cycle));
            KeyboardNavigation.ControlTabNavigationProperty.OverrideMetadata(typeof(ContextMenu), new FrameworkPropertyMetadata(KeyboardNavigationMode.Contained)); 
            KeyboardNavigation.DirectionalNavigationProperty.OverrideMetadata(typeof(ContextMenu), new FrameworkPropertyMetadata(KeyboardNavigationMode.Cycle));

            // Disable the default focus visual for ContextMenu
            FocusVisualStyleProperty.OverrideMetadata(typeof(ContextMenu), new FrameworkPropertyMetadata((object)null /* default value */)); 
        }
 
        ///  
        ///     Default ContextMenu constructor
        ///  
        /// 
        ///     Automatic determination of current Dispatcher. Use alternative constructor
        ///     that accepts a Dispatcher for best performance.
        ///  
        public ContextMenu() : base()
        { 
            Initialize(); 
        }
 
        #endregion


        #region Public Properties 

        //-------------------------------------------------------------------- 
        // 
        //  Public Properties
        // 
        //-------------------------------------------------------------------

        /// 
        ///     The DependencyProperty for the HorizontalOffset property. 
        /// 
        public static readonly DependencyProperty HorizontalOffsetProperty = 
                ContextMenuService.HorizontalOffsetProperty.AddOwner(typeof(ContextMenu), 
                            new FrameworkPropertyMetadata(null,
                                                          new CoerceValueCallback(CoerceHorizontalOffset))); 

        private static object CoerceHorizontalOffset(DependencyObject d, object value)
        {
            return PopupControlService.CoerceProperty(d, value, ContextMenuService.HorizontalOffsetProperty); 
        }
 
        ///  
        /// Get or set X offset of the ContextMenu
        ///  
        [TypeConverter(typeof(LengthConverter))]
        [Bindable(true), Category("Layout")]
        public double HorizontalOffset
        { 
            get { return (double) GetValue(HorizontalOffsetProperty); }
            set { SetValue(HorizontalOffsetProperty, value); } 
        } 

        ///  
        ///     The DependencyProperty for the VerticalOffset property.
        /// 
        public static readonly DependencyProperty VerticalOffsetProperty =
                ContextMenuService.VerticalOffsetProperty.AddOwner(typeof(ContextMenu), 
                            new FrameworkPropertyMetadata(null,
                                                          new CoerceValueCallback(CoerceVerticalOffset))); 
 
        private static object CoerceVerticalOffset(DependencyObject d, object value)
        { 
            return PopupControlService.CoerceProperty(d, value, ContextMenuService.VerticalOffsetProperty);
        }

        ///  
        /// Get or set Y offset of the ContextMenu
        ///  
        [TypeConverter(typeof(LengthConverter))] 
        [Bindable(true), Category("Layout")]
        public double VerticalOffset 
        {
            get { return (double) GetValue(VerticalOffsetProperty); }
            set { SetValue(VerticalOffsetProperty, value); }
        } 

        ///  
        /// DependencyProperty for IsOpen property 
        /// 
        public static readonly DependencyProperty IsOpenProperty = 
                Popup.IsOpenProperty.AddOwner(
                        typeof(ContextMenu),
                        new FrameworkPropertyMetadata(
                                BooleanBoxes.FalseBox, 
                                FrameworkPropertyMetadataOptions.BindsTwoWayByDefault,
                                new PropertyChangedCallback(OnIsOpenChanged))); 
 
        /// 
        /// Get or set IsOpen property of the ContextMenu 
        /// 
        [Bindable(true), Browsable(false), Category("Appearance")]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public bool IsOpen 
        {
            get { return (bool) GetValue(IsOpenProperty); } 
            set { SetValue(IsOpenProperty, BooleanBoxes.Box(value)); } 
        }
 
        private static void OnIsOpenChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            ContextMenu ctrl = (ContextMenu) d;
 
            if ((bool) e.NewValue)
            { 
                if (ctrl._parentPopup == null) 
                {
                    ctrl.HookupParentPopup(); 
                }

                ctrl._parentPopup.Unloaded += new RoutedEventHandler(ctrl.OnPopupUnloaded);
 
                // Turn on keyboard cues in case ContextMenu was opened with the keyboard
                ctrl.SetValue(KeyboardNavigation.ShowKeyboardCuesProperty, KeyboardNavigation.IsKeyboardMostRecentInputDevice()); 
            } 
            else
            { 
                ctrl.ClosingMenu();
            }
        }
 
        /// 
        ///     The DependencyProperty for the PlacementTarget property. 
        ///  
        public static readonly DependencyProperty PlacementTargetProperty =
                ContextMenuService.PlacementTargetProperty.AddOwner( 
                        typeof(ContextMenu),
                            new FrameworkPropertyMetadata(null,
                                                          new CoerceValueCallback(CoercePlacementTarget)));
 
        private static object CoercePlacementTarget(DependencyObject d, object value)
        { 
            return PopupControlService.CoerceProperty(d, value, ContextMenuService.PlacementTargetProperty); 
        }
 
        /// 
        /// Get or set PlacementTarget property of the ContextMenu
        /// 
        [Bindable(true), Category("Layout")] 
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public UIElement PlacementTarget 
        { 
            get { return (UIElement) GetValue(PlacementTargetProperty); }
            set { SetValue(PlacementTargetProperty, value); } 
        }

        /// 
        ///     The DependencyProperty for the PlacementRectangle property. 
        /// 
        public static readonly DependencyProperty PlacementRectangleProperty = 
                ContextMenuService.PlacementRectangleProperty.AddOwner(typeof(ContextMenu), 
                            new FrameworkPropertyMetadata(null,
                                                          new CoerceValueCallback(CoercePlacementRectangle))); 

        private static object CoercePlacementRectangle(DependencyObject d, object value)
        {
            return PopupControlService.CoerceProperty(d, value, ContextMenuService.PlacementRectangleProperty); 
        }
 
        ///  
        /// Get or set PlacementRectangle property of the ContextMenu
        ///  
        [Bindable(true), Category("Layout")]
        public Rect PlacementRectangle
        {
            get { return (Rect) GetValue(PlacementRectangleProperty); } 
            set { SetValue(PlacementRectangleProperty, value); }
        } 
 
        /// 
        ///     The DependencyProperty for the Placement property. 
        /// 
        public static readonly DependencyProperty PlacementProperty =
                ContextMenuService.PlacementProperty.AddOwner(typeof(ContextMenu),
                            new FrameworkPropertyMetadata(null, 
                                                          new CoerceValueCallback(CoercePlacement)));
 
        private static object CoercePlacement(DependencyObject d, object value) 
        {
            return PopupControlService.CoerceProperty(d, value, ContextMenuService.PlacementProperty); 
        }

        /// 
        /// Get or set Placement property of the ContextMenu 
        /// 
        [Bindable(true), Category("Layout")] 
        public PlacementMode Placement 
        {
            get { return (PlacementMode) GetValue(PlacementProperty); } 
            set { SetValue(PlacementProperty, value); }
        }

        ///  
        ///     The DependencyProperty for HasDropShadow
        ///  
        public static readonly DependencyProperty HasDropShadowProperty = 
                ContextMenuService.HasDropShadowProperty.AddOwner(
                        typeof(ContextMenu), 
                        new FrameworkPropertyMetadata(null,
                                                      new CoerceValueCallback(CoerceHasDropShadow)));

        private static object CoerceHasDropShadow(DependencyObject d, object value) 
        {
            ContextMenu cm = (ContextMenu)d; 
 
            if (cm._parentPopup == null || !cm._parentPopup.AllowsTransparency || !SystemParameters.DropShadow)
            { 
                return BooleanBoxes.FalseBox;
            }

            return PopupControlService.CoerceProperty(d, value, ContextMenuService.HasDropShadowProperty); 
        }
 
        ///  
        ///     Whether the control has a drop shadow.
        ///  
        public bool HasDropShadow
        {
            get { return (bool)GetValue(HasDropShadowProperty); }
            set { SetValue(HasDropShadowProperty, value); } 
        }
 
        ///  
        ///     The DependencyProperty for the CustomPopupPlacementCallback property.
        ///     Flags:              None 
        ///     Default Value:      null
        /// 
        public static readonly DependencyProperty CustomPopupPlacementCallbackProperty =
                Popup.CustomPopupPlacementCallbackProperty.AddOwner(typeof(ContextMenu)); 

        ///  
        ///     Chooses the behavior of where the ContextMenu should be placed on screen. 
        /// 
        [Bindable(false), Category("Layout")] 
        public CustomPopupPlacementCallback CustomPopupPlacementCallback
        {
            get { return (CustomPopupPlacementCallback) GetValue(CustomPopupPlacementCallbackProperty); }
            set { SetValue(CustomPopupPlacementCallbackProperty, value); } 
        }
 
        ///  
        ///     The DependencyProperty for the StaysOpen property.
        ///     Indicates that, once opened, ContextMenu should stay open until IsOpenProperty changed to 'false'. 
        ///     Flags:              None
        ///     Default Value:      false
        /// 
        public static readonly DependencyProperty StaysOpenProperty = 
                Popup.StaysOpenProperty.AddOwner(typeof(ContextMenu));
 
        ///  
        ///     Chooses the behavior of when the ContextMenu should automatically close.
        ///  
        [Bindable(true), Category("Behavior")]
        public bool StaysOpen
        {
            get { return (bool) GetValue(StaysOpenProperty); } 
            set { SetValue(StaysOpenProperty, value); }
        } 
 
        #endregion
 
        #region Events

        /// 
        ///     Opened event 
        /// 
        public static readonly RoutedEvent OpenedEvent = PopupControlService.ContextMenuOpenedEvent.AddOwner(typeof(ContextMenu)); 
 
        /// 
        ///     Event that fires when the popup opens. 
        /// 
        public event RoutedEventHandler Opened
        {
            add 
            {
                AddHandler(OpenedEvent, value); 
            } 
            remove
            { 
                RemoveHandler(OpenedEvent, value);
            }
        }
 
        /// 
        ///     Called when the OpenedEvent fires. 
        ///  
        /// 
        protected virtual void OnOpened(RoutedEventArgs e) 
        {
            RaiseEvent(e);
        }
 
        /// 
        ///     Closed event 
        ///  
        public static readonly RoutedEvent ClosedEvent = PopupControlService.ContextMenuClosedEvent.AddOwner(typeof(ContextMenu));
 
        /// 
        ///     Event that fires when the popup closes
        /// 
        public event RoutedEventHandler Closed 
        {
            add 
            { 
                AddHandler(ClosedEvent, value);
            } 
            remove
            {
                RemoveHandler(ClosedEvent, value);
            } 
        }
 
        ///  
        ///     Called when the ClosedEvent fires.
        ///  
        /// 
        protected virtual void OnClosed(RoutedEventArgs e)
        {
            RaiseEvent(e); 
        }
 
        #endregion 

 
        //--------------------------------------------------------------------
        //
        //  Protected Methods
        // 
        //--------------------------------------------------------------------
 
        #region Protected Methods 

        ///  
        /// Creates AutomationPeer ()
        /// 
        protected override System.Windows.Automation.Peers.AutomationPeer OnCreateAutomationPeer()
        { 
            return new System.Windows.Automation.Peers.ContextMenuAutomationPeer(this);
        } 
 
        /// 
        /// Prepare the element to display the item.  This may involve 
        /// applying styles, setting bindings, etc.
        /// 
        protected override void PrepareContainerForItemOverride(DependencyObject element, object item)
        { 
            base.PrepareContainerForItemOverride(element, item);
 
            MenuItem.PrepareMenuItem(element, item); 
        }
 
        /// 
        ///     If control has a scrollviewer in its style and has a custom keyboard scrolling behavior when HandlesScrolling should return true.
        /// Then ScrollViewer will not handle keyboard input and leave it up to the control.
        ///  
        protected internal override bool HandlesScrolling
        { 
            get { return true; } 
        }
 
        /// 
        ///     This is the method that responds to the KeyDown event.
        /// 
        /// Event arguments 
        protected override void OnKeyDown(KeyEventArgs e)
        { 
            base.OnKeyDown(e); 
            if (e.Handled || !IsOpen)
            { 
                // Ignore if the event was already handled or if the menu closed. This might happen
                // if input events get queued up and one in the middle caused the menu to close.
                return;
            } 

            Key key = e.Key; 
 
            switch (key)
            { 
                case Key.Down:
                    if (CurrentSelection == null)
                    {
                        NavigateToStart(new ItemNavigateArgs(e.Device, Keyboard.Modifiers)); 
                        e.Handled = true;
                    } 
 
                    break;
 
                case Key.Up:
                    if (CurrentSelection == null)
                    {
                        NavigateToEnd(new ItemNavigateArgs(e.Device, Keyboard.Modifiers)); 
                        e.Handled = true;
                    } 
 
                    break;
            } 
        }

        /// 
        ///     This is the method that responds to the KeyUp event. 
        /// 
        /// Event arguments 
        protected override void OnKeyUp(KeyEventArgs e) 
        {
            base.OnKeyUp(e); 
            if (!e.Handled && IsOpen && e.Key == Key.Apps)
            {
                    KeyboardLeaveMenuMode();
                    e.Handled = true; 
            }
        } 
 
        #endregion
 
        #region Implementation

        private static readonly DependencyProperty InsideContextMenuProperty =
            MenuItem.InsideContextMenuProperty.AddOwner(typeof(ContextMenu), 
                                                        new FrameworkPropertyMetadata(BooleanBoxes.TrueBox,
                                                                                      FrameworkPropertyMetadataOptions.Inherits)); 
 
        //-------------------------------------------------------------------
        // 
        //  Implementation
        //
        //--------------------------------------------------------------------
 
        private void Initialize()
        { 
            // We have to set this locally in order for inheritance to work 
            MenuItem.SetInsideContextMenuProperty(this, true);
 
            InternalMenuModeChanged += new EventHandler(OnIsMenuModeChanged);
        }

        private void HookupParentPopup() 
        {
            Debug.Assert(_parentPopup == null, "_parentPopup should be null"); 
 
            _parentPopup = new Popup();
 
            _parentPopup.AllowsTransparency = true;

            // Coerce HasDropShadow property in case popup can't be transparent
            CoerceValue(HasDropShadowProperty); 

            _parentPopup.DropOpposite = false; 
 
            // Listening to the Opened and Closed events lets us guarantee that
            // the popup is actually opened when we perform those functions. 
            _parentPopup.Opened += new EventHandler(OnPopupOpened);
            _parentPopup.Closed += new EventHandler(OnPopupClosed);
            _parentPopup.PopupCouldClose += new EventHandler(OnPopupCouldClose);
 
            _parentPopup.SetResourceReference(Popup.PopupAnimationProperty, SystemParameters.MenuPopupAnimationKey);
 
            // Hooks up the popup properties from this menu to the popup so that 
            // setting them on this control will also set them on the popup.
            Popup.CreateRootPopup(_parentPopup, this); 
        }

        private void OnPopupCouldClose(object sender, EventArgs e)
        { 
            SetCurrentValueInternal(IsOpenProperty, BooleanBoxes.FalseBox);
        } 
 
        private void OnPopupOpened(object source, EventArgs e)
        { 
            if (CurrentSelection != null)
            {
                CurrentSelection = null;
            } 
            IsMenuMode = true;
 
            // When we open, if the Left or Right buttons are pressed, MenuBase should not 
            // dismiss when it sees the up for those buttons.
            if (Mouse.LeftButton == MouseButtonState.Pressed) 
            {
                IgnoreNextLeftRelease = true;
            }
            if (Mouse.RightButton == MouseButtonState.Pressed) 
            {
                IgnoreNextRightRelease = true; 
            } 

            OnOpened(new RoutedEventArgs(OpenedEvent, this)); 
        }

        private void OnPopupClosed(object source, EventArgs e)
        { 
            // Clear out any state we stored for this time around
            IgnoreNextLeftRelease = false; 
            IgnoreNextRightRelease = false; 

            IsMenuMode = false; 
            OnClosed(new RoutedEventArgs(ClosedEvent, this));
        }

        private void ClosingMenu() 
        {
            if (_parentPopup != null) 
            { 
                _parentPopup.Unloaded -= new RoutedEventHandler(OnPopupUnloaded);
 
                // As the menu closes, we need the parent connection to be maintained
                // while we do things like release capture so that notifications
                // go up the tree correctly. Post this for later.
                Dispatcher.BeginInvoke(DispatcherPriority.Normal, 
                    (DispatcherOperationCallback)delegate(object arg)
                    { 
                        ContextMenu cm = (ContextMenu)arg; 
                        if (!cm.IsOpen) // Check that the menu is still closed
                        { 
                            // Prevent focus scoping from remembering the last focused element.
                            // The next time the menu opens, we want to start clean.
                            FocusManager.SetFocusedElement(cm, null);
                        } 
                        return null;
                    }, 
                    this); 
            }
        } 

        private void OnPopupUnloaded(object sender, RoutedEventArgs e)
        {
            // The tree that the ContextMenu is in is being torn down, close the menu. 

            if (IsOpen) 
            { 
                // This will be called during a tree walk, closing the menu will cause a tree change,
                // so post for later. 
                Dispatcher.BeginInvoke(DispatcherPriority.Send,
                    (DispatcherOperationCallback)delegate(object arg)
                    {
                        ContextMenu cm = (ContextMenu)arg; 
                        if (cm.IsOpen) // Check that the menu is still open
                        { 
                            cm.SetCurrentValueInternal(IsOpenProperty, BooleanBoxes.FalseBox); 
                        }
                        return null; 
                    },
                    this);
            }
        } 

        ///  
        ///     Called when IsMenuMode changes on this class 
        /// 
        private void OnIsMenuModeChanged(object sender, EventArgs e) 
        {
            // IsMenuMode changed from false to true
            if (IsMenuMode)
            { 
                // Keep the previous focus
                if (Keyboard.FocusedElement != null) 
                    _weakRefToPreviousFocus = new WeakReference(Keyboard.FocusedElement); 

                // Take focus so we get keyboard events. 
                Focus();
            }
            else // IsMenuMode changed from true to false
            { 
                SetCurrentValueInternal(IsOpenProperty, BooleanBoxes.FalseBox);
 
                // Restore the previous focus 
                if (_weakRefToPreviousFocus != null && _weakRefToPreviousFocus.IsAlive)
                    (_weakRefToPreviousFocus.Target as IInputElement).Focus(); 
            }
        }

        internal override bool IgnoreModelParentBuildRoute(RoutedEventArgs e) 
        {
            // Context menus are logically connected to their host element.  Generally, we don't 
            // want input events to route out of the context menu.  Consider the sitituation where 
            // a TextBox has a ContextMenu.  It is confusing for the text box to move the cursor
            // when I press the arrow keys while the context menu is being displayed. 
            //
            // For now we only block keyboard events and ToolTip events.  What about mouse & stylus events?
            //
            // Note: This will cause the route to not follow the logical link, but it will still 
            // follow the visual link.  At the time of writing this comment, the visual link
            // contained things like an adorner decorator.  Eventually the visual ancestory lead 
            // to a PopupRoot, which also has a logical link over to the Popup element.  Since 
            // the PopupRoot does not override this virtual, the route continues through its logical
            // link and ends up escaping into the larger logical tree anyways. 
            //
            // The solution is that the PopupRoot element (on the top of this visual tree) will
            // defer back to this method to determine if it should route any further.
            // 
            return (e is KeyEventArgs) || (e is FindToolTipEventArgs);
        } 
 
        private static void OnAccessKeyPressed(object sender, AccessKeyPressedEventArgs e)
        { 
            e.Scope = sender;
            e.Handled = true;
        }
 
        /// 
        /// Called when this element's visual parent changes 
        ///  
        /// 
        protected internal override void OnVisualParentChanged(DependencyObject oldParent) 
        {
            base.OnVisualParentChanged(oldParent);

            if (!Popup.IsRootedInPopup(_parentPopup, this)) 
            {
                throw new InvalidOperationException(SR.Get(SRID.ElementMustBeInPopup, "ContextMenu")); 
            } 
        }
 
        internal override void OnAncestorChanged()
        {
            base.OnAncestorChanged();
 
            if (!Popup.IsRootedInPopup(_parentPopup, this))
            { 
                throw new InvalidOperationException(SR.Get(SRID.ElementMustBeInPopup, "ContextMenu")); 
            }
        } 

        #endregion

        #region Private Fields 

        private Popup _parentPopup; 
        private WeakReference _weakRefToPreviousFocus; // Keep the previously focused element before CM to open 

        #endregion 

        #region DTypeThemeStyleKey

        // Returns the DependencyObjectType for the registered ThemeStyleKey's default 
        // value. Controls will override this method to return approriate types.
        internal override DependencyObjectType DTypeThemeStyleKey 
        { 
            get { return _dType; }
        } 

        private static DependencyObjectType _dType;

        #endregion DTypeThemeStyleKey 

    } 
} 

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
// Copyright (c) Microsoft Corporation. All rights reserved.


                        

Link Menu

Network programming in C#, Network Programming in VB.NET, Network Programming in .NET
This book is available now!
Buy at Amazon US or
Buy at Amazon UK