MenuItem.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 / MenuItem.cs / 1305600 / MenuItem.cs

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

using System; 
using MS.Internal; 
using MS.Internal.KnownBoxes;
using MS.Utility; 
using System.Diagnostics;
using System.Windows.Threading;
using System.Globalization;
 
using System.ComponentModel;
using System.Collections; 
using System.Collections.Specialized; 
using System.Security;
using System.Security.Permissions; 


using System.Windows;
using System.Windows.Automation.Peers; 
using System.Windows.Data;
using System.Windows.Media; 
using System.Windows.Input; 

using System.Windows.Controls.Primitives; 
using System.Windows.Shapes;
using System.Windows.Markup;

// Disable CS3001: Warning as Error: not CLS-compliant 
#pragma warning disable 3001
 
namespace System.Windows.Controls 
{
    ///  
    ///     Defines the different placement types of MenuItems.
    /// 
    public enum MenuItemRole
    { 
        /// 
        ///     A top-level menu item that can invoke commands. 
        ///  
        TopLevelItem,
 
        /// 
        ///     Header for top-level menus.
        /// 
        TopLevelHeader, 

        ///  
        ///     A menu item in a submenu that can invoke commands. 
        /// 
        SubmenuItem, 

        /// 
        ///     A header for a submenu.
        ///  
        SubmenuHeader,
    } 
 
    /// 
    ///     A child item of Menu. 
    ///     MenuItems can be selected to invoke commands.
    ///     MenuItems can be headers for submenus.
    ///     MenuItems can be checked or unchecked.
    ///  
    [DefaultEvent("Click")]
    [Localizability(LocalizationCategory.Menu)] 
    [TemplatePart(Name = "PART_Popup", Type = typeof(Popup))] 
    [StyleTypedProperty(Property = "ItemContainerStyle", StyleTargetType = typeof(MenuItem))]
    public class MenuItem : HeaderedItemsControl, ICommandSource 
    {

        // ---------------------------------------------------------------------------
        //  Defines the names of the resources to be consumed by the MenuItem style. 
        //  Used to restyle several roles of MenuItem without having to restyle
        //  all of the control. 
        // --------------------------------------------------------------------------- 

        #region StyleKeys 

        /// 
        /// Key used to mark the template for use by TopLevel MenuItems
        ///  
        public static ResourceKey TopLevelItemTemplateKey
        { 
            get 
            {
                if (_topLevelItemTemplateKey == null) 
                {
                    _topLevelItemTemplateKey = new ComponentResourceKey(typeof(MenuItem), "TopLevelItemTemplateKey");
                }
 
                return _topLevelItemTemplateKey;
            } 
        } 

        ///  
        /// Key used to mark the template for use by TopLevel Menu Header
        /// 
        public static ResourceKey TopLevelHeaderTemplateKey
        { 
            get
            { 
                if (_topLevelHeaderTemplateKey == null) 
                {
                    _topLevelHeaderTemplateKey = new ComponentResourceKey(typeof(MenuItem), "TopLevelHeaderTemplateKey"); 
                }

                return _topLevelHeaderTemplateKey;
            } 
        }
 
        ///  
        /// Key used to mark the template for use by Submenu Item
        ///  
        public static ResourceKey SubmenuItemTemplateKey
        {
            get
            { 
                if (_submenuItemTemplateKey == null)
                { 
                    _submenuItemTemplateKey = new ComponentResourceKey(typeof(MenuItem), "SubmenuItemTemplateKey"); 
                }
 
                return _submenuItemTemplateKey;
            }
        }
 
        /// 
        /// Key used to mark the template for use by Submenu Header 
        ///  
        public static ResourceKey SubmenuHeaderTemplateKey
        { 
            get
            {
                if (_submenuHeaderTemplateKey == null)
                { 
                    _submenuHeaderTemplateKey = new ComponentResourceKey(typeof(MenuItem), "SubmenuHeaderTemplateKey");
                } 
 
                return _submenuHeaderTemplateKey;
            } 
        }

        private static ComponentResourceKey _topLevelItemTemplateKey;
        private static ComponentResourceKey _topLevelHeaderTemplateKey; 
        private static ComponentResourceKey _submenuItemTemplateKey;
        private static ComponentResourceKey _submenuHeaderTemplateKey; 
 
        #endregion
 
        //--------------------------------------------------------------------
        //
        //  Constructors
        // 
        //-------------------------------------------------------------------
 
        #region Constructors 

        ///  
        ///     Default MenuItem constructor
        /// 
        public MenuItem() : base()
        { 
        }
 
        static MenuItem() 
        {
            HeaderProperty.OverrideMetadata(typeof(MenuItem), new FrameworkPropertyMetadata(null, new CoerceValueCallback(CoerceHeader))); 

            EventManager.RegisterClassHandler(typeof(MenuItem), AccessKeyManager.AccessKeyPressedEvent, new AccessKeyPressedEventHandler(OnAccessKeyPressed));
            EventManager.RegisterClassHandler(typeof(MenuItem), MenuBase.IsSelectedChangedEvent, new RoutedPropertyChangedEventHandler(OnIsSelectedChanged));
 
            ForegroundProperty.OverrideMetadata(typeof(MenuItem), new FrameworkPropertyMetadata(SystemColors.MenuTextBrush));
            FontFamilyProperty.OverrideMetadata(typeof(MenuItem), new FrameworkPropertyMetadata(SystemFonts.MessageFontFamily)); 
            FontSizeProperty.OverrideMetadata(typeof(MenuItem), new FrameworkPropertyMetadata(SystemFonts.MessageFontSize)); 
            FontStyleProperty.OverrideMetadata(typeof(MenuItem), new FrameworkPropertyMetadata(SystemFonts.MessageFontStyle));
            FontWeightProperty.OverrideMetadata(typeof(MenuItem), new FrameworkPropertyMetadata(SystemFonts.MessageFontWeight)); 

            // Disable tooltips on menu item when submenu is open
            ToolTipService.IsEnabledProperty.OverrideMetadata(typeof(MenuItem), new FrameworkPropertyMetadata(null, new CoerceValueCallback(CoerceToolTipIsEnabled)));
 
#if OLD_AUTOMATION
            AutomationProvider.AcceleratorKeyProperty.OverrideMetadata(typeof(MenuItem), new FrameworkPropertyMetadata(null, (PropertyChangedCallback)null, new CoerceValueCallback(OnCoerceAcceleratorKey))); 
#endif 

            DefaultStyleKeyProperty.OverrideMetadata(typeof(MenuItem), new FrameworkPropertyMetadata(typeof(MenuItem))); 
            _dType = DependencyObjectType.FromSystemTypeInternal(typeof(MenuItem));

            KeyboardNavigation.DirectionalNavigationProperty.OverrideMetadata(typeof(MenuItem), new FrameworkPropertyMetadata(KeyboardNavigationMode.None));
 
            // Disable default focus visual for MenuItem.
            FocusVisualStyleProperty.OverrideMetadata(typeof(MenuItem), new FrameworkPropertyMetadata((object)null /* default value */)); 
 

            // While the menu is opened, Input Method should be suspended. 
            // the docusmen focus of Cicero should not be changed but key typing should not be
            // dispatched to IME/TIP.
            InputMethod.IsInputMethodSuspendedProperty.OverrideMetadata(typeof(MenuItem), new FrameworkPropertyMetadata(BooleanBoxes.TrueBox, FrameworkPropertyMetadataOptions.Inherits));
        } 

        #endregion 
 
        //--------------------------------------------------------------------
        // 
        //  Public Events
        //
        //--------------------------------------------------------------------
 
        #region Public Events
 
        ///  
        ///     Event corresponds to left mouse button click
        ///  
        public static readonly RoutedEvent ClickEvent = EventManager.RegisterRoutedEvent("Click", RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(MenuItem));

        /// 
        ///     Add / Remove Click handler 
        /// 
        [Category("Behavior")] 
        public event RoutedEventHandler Click 
        {
            add 
            {
                AddHandler(MenuItem.ClickEvent, value);
            }
 
            remove
            { 
                RemoveHandler(MenuItem.ClickEvent, value); 
            }
        } 

        /// 
        ///     Event that is fired when mouse button is pressed down but before menus are closed.
        ///     This event should be handled by the parent menu and used to know when to close all submenus. 
        /// 
        internal static readonly RoutedEvent PreviewClickEvent = EventManager.RegisterRoutedEvent("PreviewClick", RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(MenuItem)); 
 
        /// 
        ///     Checked event 
        /// 
        public static readonly RoutedEvent CheckedEvent = EventManager.RegisterRoutedEvent("Checked", RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(MenuItem));

        ///  
        ///     Unchecked event
        ///  
        public static readonly RoutedEvent UncheckedEvent = EventManager.RegisterRoutedEvent("Unchecked", RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(MenuItem)); 

        ///  
        ///     Add / Remove Checked handler
        /// 
        [Category("Behavior")]
        public event RoutedEventHandler Checked 
        {
            add 
            { 
                AddHandler(CheckedEvent, value);
            } 

            remove
            {
                RemoveHandler(CheckedEvent, value); 
            }
        } 
 
        /// 
        ///     Add / Remove Unchecked handler 
        /// 
        [Category("Behavior")]
        public event RoutedEventHandler Unchecked
        { 
            add
            { 
                AddHandler(UncheckedEvent, value); 
            }
 
            remove
            {
                RemoveHandler(UncheckedEvent, value);
            } 
        }
 
 
        /// 
        ///     Event fires when submenu opens 
        /// 
        public static readonly RoutedEvent SubmenuOpenedEvent =
            EventManager.RegisterRoutedEvent("SubmenuOpened", RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(MenuItem));
 
        /// 
        ///     Event fires when submenu closes 
        ///  
        public static readonly RoutedEvent SubmenuClosedEvent =
            EventManager.RegisterRoutedEvent("SubmenuClosed", RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(MenuItem)); 

        /// 
        ///     Add / Remove SubmenuOpenedEvent handler
        ///  
        [Category("Behavior")]
        public event RoutedEventHandler SubmenuOpened 
        { 
            add
            { 
                AddHandler(SubmenuOpenedEvent, value);
            }
            remove
            { 
                RemoveHandler(SubmenuOpenedEvent, value);
            } 
        } 

        ///  
        ///     Add / Remove SubmenuClosedEvent handler
        /// 
        [Category("Behavior")]
        public event RoutedEventHandler SubmenuClosed 
        {
            add 
            { 
                AddHandler(SubmenuClosedEvent, value);
            } 
            remove
            {
                RemoveHandler(SubmenuClosedEvent, value);
            } 
        }
 
        #endregion 

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

        #region Public Properties 
 
        // Set the header to the command text if no header has been explicitly specified
        private static object CoerceHeader(DependencyObject d, object value) 
        {
            MenuItem menuItem = (MenuItem)d;
            RoutedUICommand uiCommand;
 
            // If no header has been set, use the command's text
            if (value == null && !menuItem.HasNonDefaultValue(HeaderProperty)) 
            { 
                uiCommand = menuItem.Command as RoutedUICommand;
                if (uiCommand != null) 
                {
                    value = uiCommand.Text;
                }
                return value; 
            }
 
            // If the header had been set to a UICommand by the ItemsControl, replace it with the command's text 
            uiCommand = value as RoutedUICommand;
 
            if (uiCommand != null)
            {
                // The header is equal to the command.
                // If this MenuItem was generated for the command, then go ahead and overwrite the header 
                // since the generator automatically set the header.
                ItemsControl parent = ItemsControl.ItemsControlFromItemContainer(menuItem); 
                if (parent != null) 
                {
                    object originalItem = parent.ItemContainerGenerator.ItemFromContainer(menuItem); 

                    if (originalItem == value)
                    {
                        return uiCommand.Text; 
                    }
                } 
            } 

            return value; 
        }

        /// 
        ///     The DependencyProperty for the RoutedCommand. 
        ///     Flags:              None
        ///     Default Value:      null 
        ///  
        public static readonly DependencyProperty CommandProperty =
                ButtonBase.CommandProperty.AddOwner( 
                        typeof(MenuItem),
                        new FrameworkPropertyMetadata(
                                (ICommand)null,
                                new PropertyChangedCallback(OnCommandChanged))); 

        ///  
        ///     The MenuItem's Command. 
        /// 
        [Bindable(true), Category("Action")] 
        [Localizability(LocalizationCategory.NeverLocalize)]
        public ICommand Command
        {
            get { return (ICommand) GetValue(CommandProperty); } 
            set { SetValue(CommandProperty, value); }
        } 
 
        private static void OnCommandChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        { 
            MenuItem item = (MenuItem) d;
            item.OnCommandChanged((ICommand) e.OldValue, (ICommand) e.NewValue);
        }
 
        private void OnCommandChanged(ICommand oldCommand, ICommand newCommand)
        { 
            if (oldCommand != null) 
            {
                UnhookCommand(oldCommand); 
            }
            if (newCommand != null)
            {
                HookCommand(newCommand); 
            }
 
            CoerceValue(HeaderProperty); 
            CoerceValue(InputGestureTextProperty);
        } 

        private void UnhookCommand(ICommand command)
        {
            EventHandler handler = CanExecuteChangedHandler.GetValue(this); 
            if (handler != null)
            { 
                command.CanExecuteChanged -= handler; 
                CanExecuteChangedHandler.ClearValue(this);
            } 
            UpdateCanExecute();
        }

        private void HookCommand(ICommand command) 
        {
            EventHandler handler = new EventHandler(OnCanExecuteChanged); 
            CanExecuteChangedHandler.SetValue(this, handler); 
            command.CanExecuteChanged += handler;
            UpdateCanExecute(); 
        }

        private void OnCanExecuteChanged(object sender, EventArgs e)
        { 
            UpdateCanExecute();
        } 
 
        private void UpdateCanExecute()
        { 
            MenuItem.SetBoolField(this, BoolField.CanExecuteInvalid, false);
            if (Command != null)
            {
                // Perf optimization - only raise CanExecute event if the menu is open 
                MenuItem parent = ItemsControl.ItemsControlFromItemContainer(this) as MenuItem;
                if (parent == null || parent.IsSubmenuOpen) 
                { 
                    CanExecute = MS.Internal.Commands.CommandHelpers.CanExecuteCommandSource(this);
                } 
                else
                {
                    CanExecute = true;
                    MenuItem.SetBoolField(this, BoolField.CanExecuteInvalid, true); 
                }
            } 
            else 
            {
                CanExecute = true; 
            }
        }

        ///  
        ///     Fetches the value of the IsEnabled property
        ///  
        ///  
        ///     The reason this property is overridden is so that MenuItem
        ///     can infuse the value for CanExecute into it. 
        /// 
        protected override bool IsEnabledCore
        {
            get 
            {
                return base.IsEnabledCore && CanExecute; 
            } 
        }
 

        /// 
        ///     The DependencyProperty for the RoutedCommand's parameter.
        ///     Flags:              None 
        ///     Default Value:      null
        ///  
        public static readonly DependencyProperty CommandParameterProperty = 
                ButtonBase.CommandParameterProperty.AddOwner(
                        typeof(MenuItem), 
                        new FrameworkPropertyMetadata((object) null));

        /// 
        ///     The parameter to pass to MenuItem's Command. 
        /// 
        [Bindable(true), Category("Action")] 
        [Localizability(LocalizationCategory.NeverLocalize)] 
        public object CommandParameter
        { 
            get { return GetValue(CommandParameterProperty); }
            set { SetValue(CommandParameterProperty, value); }
        }
 
        /// 
        ///     The DependencyProperty for Target property 
        ///     Flags:              None 
        ///     Default Value:      null
        ///  
        public static readonly DependencyProperty CommandTargetProperty =
                ButtonBase.CommandTargetProperty.AddOwner(
                        typeof(MenuItem),
                        new FrameworkPropertyMetadata((IInputElement) null)); 

        ///  
        ///     The target element on which to fire the command. 
        /// 
        [Bindable(true), Category("Action")] 
        public IInputElement CommandTarget
        {
            get { return (IInputElement)GetValue(CommandTargetProperty); }
            set { SetValue(CommandTargetProperty, value); } 
        }
 
        ///  
        ///     The DependencyProperty for the IsSubmenuOpen property.
        ///     Flags:              None 
        ///     Default Value:      false
        /// 
        public static readonly DependencyProperty IsSubmenuOpenProperty =
                DependencyProperty.Register( 
                        "IsSubmenuOpen",
                        typeof(bool), 
                        typeof(MenuItem), 
                        new FrameworkPropertyMetadata(
                                BooleanBoxes.FalseBox, 
                                FrameworkPropertyMetadataOptions.BindsTwoWayByDefault,
                                new PropertyChangedCallback(OnIsSubmenuOpenChanged),
                                new CoerceValueCallback(CoerceIsSubmenuOpen)));
        ///  
        ///     When the MenuItem's submenu is visible.
        ///  
        [Bindable(true), Browsable(false), Category("Appearance")] 
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public bool IsSubmenuOpen 
        {
            get { return (bool) GetValue(IsSubmenuOpenProperty); }
            set { SetValue(IsSubmenuOpenProperty, BooleanBoxes.Box(value)); }
        } 

        private static object CoerceIsSubmenuOpen(DependencyObject d, object value) 
        { 
            if ((bool) value)
            { 
                MenuItem mi = (MenuItem) d;
                if (!mi.IsLoaded)
                {
                    mi.RegisterToOpenOnLoad(); 
                    return BooleanBoxes.FalseBox;
                } 
            } 

            return value; 
        }

        // Disable tooltips on opened menu items
        private static object CoerceToolTipIsEnabled(DependencyObject d, object value) 
        {
            MenuItem mi = (MenuItem) d; 
            return mi.IsSubmenuOpen ? BooleanBoxes.FalseBox : value; 
        }
 
        private void RegisterToOpenOnLoad()
        {
            Loaded += new RoutedEventHandler(OpenOnLoad);
        } 

        private void OpenOnLoad(object sender, RoutedEventArgs e) 
        { 
            // Open menu after it has rendered (Loaded is fired before 1st render)
            Dispatcher.BeginInvoke(DispatcherPriority.Input, new DispatcherOperationCallback(delegate(object param) 
            {
                CoerceValue(IsSubmenuOpenProperty);

                return null; 
            }), null);
        } 
 
        /// 
        ///     Called when IsSubmenuOpenID is invalidated on "d." 
        /// 
        private static void OnIsSubmenuOpenChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            MenuItem menuItem = (MenuItem)d; 

            bool oldValue = (bool) e.OldValue; 
            bool newValue = (bool) e.NewValue; 
            // The IsSubmenuOpen value has changed; this should stop any timers
            // we may have set to open/close the menus. 
            menuItem.StopTimer(ref menuItem._openHierarchyTimer);
            menuItem.StopTimer(ref menuItem._closeHierarchyTimer);

            MenuItemAutomationPeer peer = UIElementAutomationPeer.FromElement(menuItem) as MenuItemAutomationPeer; 
            if (peer != null)
            { 
                peer.ResetChildrenCache(); 
                peer.RaiseExpandCollapseAutomationEvent(oldValue, newValue);
            } 

            if (newValue)
            {
                CommandManager.InvalidateRequerySuggested(); // Should post an idle queue item to update IsEnabled on commands 

                // When menuitem's submenu opens, it should be selected. 
                menuItem.SetCurrentValueInternal(IsSelectedProperty, BooleanBoxes.TrueBox); 

                MenuItemRole role = menuItem.Role; 
                if (role == MenuItemRole.TopLevelHeader)
                {
                    menuItem.SetMenuMode(true);
                } 
                menuItem.CurrentSelection = null;
 
                // When our submenu opens, update our siblings so they do not animate 
                menuItem.NotifySiblingsToSuspendAnimation();
 
                // Force update of CanExecute when opening menu.
                for (int i = 0; i < menuItem.Items.Count; i++)
                {
                    MenuItem subItem = menuItem.ItemContainerGenerator.ContainerFromIndex(i) as MenuItem; 
                    if (subItem != null && MenuItem.GetBoolField(subItem, BoolField.CanExecuteInvalid))
                    { 
                        subItem.UpdateCanExecute(); 
                    }
                } 

                menuItem.OnSubmenuOpened(new RoutedEventArgs(SubmenuOpenedEvent, menuItem));

 
                MenuItem.SetBoolField(menuItem, BoolField.IgnoreMouseEvents, true);
                MenuItem.SetBoolField(menuItem, BoolField.MouseEnterOnMouseMove, false); 
 
                // MenuItem should ignore any mouse enter or move events until the menu has fully
                // opened.  Otherwise we may highlight a menu item under the mouse even though 
                // the user opened the menu with the keyboard
                // This is fired below input priority so any mouse events happen before setting the flag
                menuItem.Dispatcher.BeginInvoke(DispatcherPriority.Background, new DispatcherOperationCallback(delegate(object param)
                { 
                    MenuItem.SetBoolField(menuItem, BoolField.IgnoreMouseEvents, false);
                    return null; 
                }), null); 
            }
            else 
            {
                // Our submenu is closing, so close our submenu's submenu
                if (menuItem.CurrentSelection != null)
                { 
                    // We're about to close the submenu -- if focus is within
                    // the subtree, we need to take it back so that Focus isn't 
                    // left in an orphaned tree. 
                    if (menuItem.CurrentSelection.IsKeyboardFocusWithin)
                    { 
                        menuItem.Focus();
                    }

                    if (menuItem.CurrentSelection.IsSubmenuOpen) 
                    {
                        menuItem.CurrentSelection.SetCurrentValueInternal(IsSubmenuOpenProperty, BooleanBoxes.FalseBox); 
                    } 
                }
                else 
                {
                    // We need to take focus out of the subtree if we close
                    // the submenu.  Above we can be sure that focus will be
                    // on the selected item so we just need to check if IsFocusWithin 
                    // is true on the selected item.  If we have no CurrentSelection,
                    // we have to be a little more aggressive and take focus 
                    // back if IsFocusWithin is true. 
                    //
                    // NOTE: This could potentially steal focus back from something 
                    //       within the menuitem's header (say, a TextBox) but it is
                    //       unlikely that focus will be within a header while the submenu
                    //       is open.
 
                    if (menuItem.IsKeyboardFocusWithin)
                    { 
                        if (!menuItem.Focus()) 
                        {
                            // Shoot, we couldn't take focus out of the submenu 
                            // and put it back on ourselves.  Now focus is in a
                            // disconnected subtree.  Ultimately core input will
                            // disallow this, presumably by setting focus to null.
                            // For now we won't handle this case. 
                        }
                    } 
                } 

                menuItem.CurrentSelection = null; 

                if ((menuItem.IsMouseOver) && (menuItem.Role == MenuItemRole.SubmenuHeader))
                {
                    // If the mouse is inside the subtree, then we will get a mouse leave, but we want to ignore it 
                    // to maintain the highlight.
                    MenuItem.SetBoolField(menuItem, BoolField.IgnoreNextMouseLeave, true); 
                } 

                // When our submenu closes, update our children so they will animate 
                menuItem.NotifyChildrenToResumeAnimation();

                // No Popup in the style so fire closed now
                if (menuItem._submenuPopup == null) 
                {
                    menuItem.OnSubmenuClosed(new RoutedEventArgs(SubmenuClosedEvent, menuItem)); 
                } 
            }
 
            menuItem.CoerceValue(ToolTipService.IsEnabledProperty);
        }

        private void OnPopupClosed(object source, EventArgs e) 
        {
            OnSubmenuClosed(new RoutedEventArgs(SubmenuClosedEvent, this)); 
        } 

        ///  
        ///
        /// 
        /// 
        protected virtual void OnSubmenuOpened(RoutedEventArgs e) 
        {
            RaiseEvent(e); 
        } 

        ///  
        ///
        /// 
        /// 
        protected virtual void OnSubmenuClosed(RoutedEventArgs e) 
        {
            RaiseEvent(e); 
        } 

        ///  
        ///     The key needed set a read-only property.
        /// 
        private static readonly DependencyPropertyKey RolePropertyKey =
                DependencyProperty.RegisterReadOnly( 
                        "Role",
                        typeof(MenuItemRole), 
                        typeof(MenuItem), 
                        new FrameworkPropertyMetadata(MenuItemRole.TopLevelItem));
 
        /// 
        ///     The DependencyProperty for the Role property.
        ///     Flags:              None
        ///     Default Value:      MenuItemRole.TopLevelItem 
        /// 
        public static readonly DependencyProperty RoleProperty = 
                RolePropertyKey.DependencyProperty; 

        ///  
        ///     What the role of the menu item is: TopLevelItem, TopLevelHeader, SubmenuItem, SubmenuHeader.
        /// 
        [Category("Behavior")]
        public MenuItemRole Role 
        {
            get { return (MenuItemRole) GetValue(RoleProperty); } 
        } 

        private void UpdateRole() 
        {
            MenuItemRole type;

            if (!IsCheckable && HasItems) 
            {
                if (LogicalParent is Menu) 
                { 
                    type = MenuItemRole.TopLevelHeader;
                } 
                else
                {
                    type = MenuItemRole.SubmenuHeader;
                } 
            }
            else 
            { 
                if (LogicalParent is Menu)
                { 
                    type = MenuItemRole.TopLevelItem;
                }
                else
                { 
                    type = MenuItemRole.SubmenuItem;
                } 
            } 

            SetValue(RolePropertyKey, type); 
        }

        /// 
        ///     The DependencyProperty for the IsCheckable property. 
        ///     Flags:              None
        ///     Default Value:      false 
        ///  
        public static readonly DependencyProperty IsCheckableProperty =
                DependencyProperty.Register( 
                        "IsCheckable",
                        typeof(bool),
                        typeof(MenuItem),
                        new FrameworkPropertyMetadata( 
                                BooleanBoxes.FalseBox,
                                new PropertyChangedCallback(OnIsCheckableChanged))); 
 
        /// 
        ///     IsCheckable determines the user ability to check/uncheck the item. 
        /// 
        [Bindable(true), Category("Behavior")]
        public bool IsCheckable
        { 
            get { return (bool)GetValue(IsCheckableProperty); }
            set { SetValue(IsCheckableProperty, value); } 
        } 

        private static void OnIsCheckableChanged(DependencyObject target, DependencyPropertyChangedEventArgs e) 
        {
            ((MenuItem) target).UpdateRole();
        }
 
        /// 
        ///     The DependencyPropertyKey for the IsPressed property. 
        ///     Flags:              None 
        ///     Default Value:      false
        ///  
        private static readonly DependencyPropertyKey IsPressedPropertyKey =
                DependencyProperty.RegisterReadOnly(
                        "IsPressed",
                        typeof(bool), 
                        typeof(MenuItem),
                        new FrameworkPropertyMetadata(BooleanBoxes.FalseBox)); 
 
        /// 
        ///     The DependencyProperty for the IsPressed property. 
        ///     Flags:              None
        ///     Default Value:      false
        /// 
        public static readonly DependencyProperty IsPressedProperty = IsPressedPropertyKey.DependencyProperty; 

        ///  
        ///     When the MenuItem is pressed. 
        /// 
        [Browsable(false), Category("Appearance")] 
        public bool IsPressed
        {
            get { return (bool) GetValue(IsPressedProperty); }
            protected set { SetValue(IsPressedPropertyKey, BooleanBoxes.Box(value)); } 
        }
 
        private void UpdateIsPressed() 
        {
            Rect itemBounds = new Rect(new Point(), RenderSize); 

            if ((Mouse.LeftButton == MouseButtonState.Pressed) &&
                IsMouseOver &&
                itemBounds.Contains(Mouse.GetPosition(this))) 
            {
                IsPressed = true; 
            } 
            else
            { 
                ClearValue(IsPressedPropertyKey);
            }
        }
 
        /// 
        ///     The key needed set a read-only property. 
        ///  
        private static readonly DependencyPropertyKey IsHighlightedPropertyKey =
                DependencyProperty.RegisterReadOnly( 
                        "IsHighlighted",
                        typeof(bool),
                        typeof(MenuItem),
                        new FrameworkPropertyMetadata(BooleanBoxes.FalseBox)); 

        ///  
        ///     The DependencyProperty for the IsHighlighted property. 
        ///     Flags:              None
        ///     Default Value:      false 
        /// 
        public static readonly DependencyProperty IsHighlightedProperty =
                IsHighlightedPropertyKey.DependencyProperty;
 
        /// 
        ///     Whether the MenuItem should be highlighted. 
        ///  
        [Browsable(false), Category("Appearance")]
        public bool IsHighlighted 
        {
            get { return (bool) GetValue(IsHighlightedProperty); }
            protected set { SetValue(IsHighlightedPropertyKey, BooleanBoxes.Box(value)); }
        } 

        ///  
        ///     The DependencyProperty for the IsChecked property. 
        ///     Flags:              None
        ///     Default Value:      false 
        /// 
        public static readonly DependencyProperty IsCheckedProperty =
                DependencyProperty.Register(
                        "IsChecked", 
                        typeof(bool),
                        typeof(MenuItem), 
                        new FrameworkPropertyMetadata( 
                                BooleanBoxes.FalseBox,
                                FrameworkPropertyMetadataOptions.BindsTwoWayByDefault | FrameworkPropertyMetadataOptions.Journal, 
                                new PropertyChangedCallback(OnIsCheckedChanged)));

        /// 
        ///     When the MenuItem is checked. 
        /// 
        [Bindable(true), Category("Appearance")] 
        public bool IsChecked 
        {
            get { return (bool) GetValue(IsCheckedProperty); } 
            set { SetValue(IsCheckedProperty, BooleanBoxes.Box(value)); }
        }

        ///  
        ///     Called when IsChecked becomes true.
        ///  
        /// Event arguments for the routed event that is raised by the default implementation of this method. 
        protected virtual void OnChecked(RoutedEventArgs e)
        { 
            RaiseEvent(e);
        }

        ///  
        ///     Called when IsChecked becomes false.
        ///  
        /// Event arguments for the routed event that is raised by the default implementation of this method. 
        protected virtual void OnUnchecked(RoutedEventArgs e)
        { 
            RaiseEvent(e);
        }

        ///  
        ///     Called when IsCheckedProperty is invalidated on "d."
        ///  
        private static void OnIsCheckedChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) 
        {
            MenuItem menuItem = (MenuItem) d; 

            if ((bool) e.NewValue)
            {
                menuItem.OnChecked(new RoutedEventArgs(CheckedEvent)); 
            }
            else 
            { 
                menuItem.OnUnchecked(new RoutedEventArgs(UncheckedEvent));
            } 
        }

        /// 
        ///     The DependencyProperty for the StaysOpenOnClick property. 
        ///     Flags:              None
        ///     Default Value:      false 
        ///  
        public static readonly DependencyProperty StaysOpenOnClickProperty =
                DependencyProperty.Register( 
                        "StaysOpenOnClick",
                        typeof(bool),
                        typeof(MenuItem),
                        new FrameworkPropertyMetadata(BooleanBoxes.FalseBox)); 

        ///  
        ///     Indicates that the submenu that this MenuItem is within should not close when this item is clicked. 
        /// 
        [Bindable(true), Category("Behavior")] 
        public bool StaysOpenOnClick
        {
            get { return (bool) GetValue(StaysOpenOnClickProperty); }
            set { SetValue(StaysOpenOnClickProperty, BooleanBoxes.Box(value)); } 
        }
 
        ///  
        ///     True if this MenuItem is the current MenuItem of its parent.
        ///     Focus drives Selection, but not vice versa.  This will enable 
        ///     focusless menus.
        /// 
        internal bool IsSelected
        { 
            get { return (bool) GetValue(IsSelectedProperty); }
            set { SetValue(IsSelectedProperty, BooleanBoxes.Box(value)); } 
        } 

        ///  
        ///     DependencyProperty for IsSelected property.
        /// 
        internal static readonly DependencyProperty IsSelectedProperty =
                Selector.IsSelectedProperty.AddOwner( 
                        typeof(MenuItem),
                        new FrameworkPropertyMetadata( 
                                BooleanBoxes.FalseBox, 
                                FrameworkPropertyMetadataOptions.BindsTwoWayByDefault,
                                new PropertyChangedCallback(OnIsSelectedChanged))); 

        private static void OnIsSelectedChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            MenuItem menuItem = (MenuItem)d; 
            // When IsSelected changes, IsHighlighted should reflect IsSelected
            // Note: it is okay for IsHighlighted and IsSelected to be different. 
            //       Selection and highlight will separate when mousing around in 
            //       a submenu when any timers are active.  Until you hover long
            //       enough and your selection is "committed", selection and highlight 
            //       can disagree.
            menuItem.SetValue(IsHighlightedPropertyKey, e.NewValue);

            // If IsSelected is changing to false, make sure to close 
            // our submenu before doing anything.
            if ((bool) e.OldValue) 
            { 
                if (menuItem.IsSubmenuOpen)
                { 
                    menuItem.SetCurrentValueInternal(IsSubmenuOpenProperty, BooleanBoxes.FalseBox);
                }

                // Also stop any timers immediately when we become deselected. 
                menuItem.StopTimer(ref menuItem._openHierarchyTimer);
                menuItem.StopTimer(ref menuItem._closeHierarchyTimer); 
            } 

            menuItem.RaiseEvent(new RoutedPropertyChangedEventArgs((bool) e.OldValue, (bool) e.NewValue, MenuBase.IsSelectedChangedEvent)); 
        }

        /// 
        ///     Called when IsSelected changed on this element or any descendant. 
        /// 
        private static void OnIsSelectedChanged(object sender, RoutedPropertyChangedEventArgs e) 
        { 
            // If IsSelected changed on a child of the MenuItem, change CurrentSelection
            // to the element that sent the event and handle the event. 
            if (sender != e.OriginalSource)
            {
                MenuItem menuItem = (MenuItem)sender;
                MenuItem source = e.OriginalSource as MenuItem; 

                if (source != null) 
                { 
                    if (e.NewValue)
                    { 
                        // If the item is now selected, we should stop any timers which will
                        // close the submenu.  This is for the case where one mouses out of
                        // the current selection but then comes back.
                        if (menuItem.CurrentSelection == source) 
                        {
                            menuItem.StopTimer(ref menuItem._closeHierarchyTimer); 
                        } 

                        // If the MenuItem is selected and it's a new item that's a child of ours, 
                        // change the CurrentSelection.
                        if (menuItem.CurrentSelection != source && source.LogicalParent == menuItem)
                        {
                            if (menuItem.CurrentSelection != null && menuItem.CurrentSelection.IsSubmenuOpen) 
                            {
                                menuItem.CurrentSelection.SetCurrentValueInternal(IsSubmenuOpenProperty, BooleanBoxes.FalseBox); 
                            } 

                            menuItem.CurrentSelection = source; 
                        }
                    }
                    else
                    { 
                        // If the item is no longer selected
                        // If the MenuItem has been deselected and it's the CurrentSelection, 
                        // set our CurrentSelection to null. 
                        if (menuItem.CurrentSelection == source)
                        { 
                            menuItem.CurrentSelection = null;
                        }
                    }
 
                    // Mark the event as handled as long as it came from a MenuItem underneath us
                    // even if we didn't necessarily do anything. 
                    e.Handled = true; 
                }
            } 
        }

        /// 
        ///     The DependencyProperty for the InputGestureText property. 
        ///     Default Value:      String.Empty
        ///  
        public static readonly DependencyProperty InputGestureTextProperty = 
                DependencyProperty.Register(
                        "InputGestureText", 
                        typeof(string),
                        typeof(MenuItem),
                        new FrameworkPropertyMetadata(String.Empty,
                                                      new PropertyChangedCallback(OnInputGestureTextChanged), 
                                                      new CoerceValueCallback(CoerceInputGestureText)));
 
        ///  
        ///     Text describing an input gesture that will invoke the command tied to this item.
        ///  
        [Bindable(true), CustomCategory("Content")]
        public string InputGestureText
        {
            get { return (string) GetValue(InputGestureTextProperty); } 
            set { SetValue(InputGestureTextProperty, value); }
        } 
 
        private static void OnInputGestureTextChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        { 
#if OLD_AUTOMATION
            d.CoerceValue(AutomationProvider.AcceleratorKeyProperty);
#endif
        } 

        // Gets the input gesture text from the command text if it hasn't been explicitly specified 
        private static object CoerceInputGestureText(DependencyObject d, object value) 
        {
            MenuItem menuItem = (MenuItem)d; 
            RoutedCommand routedCommand;

            if (String.IsNullOrEmpty((string)value) && !menuItem.HasNonDefaultValue(InputGestureTextProperty)
                && (routedCommand = menuItem.Command as RoutedCommand) != null ) 
            {
                InputGestureCollection col = routedCommand.InputGestures; 
                if ((col != null) && (col.Count >= 1)) 
                {
                    // Search for the first key gesture 
                    for (int i = 0; i < col.Count; i++)
                    {
                        KeyGesture keyGesture = ((IList)col)[i] as KeyGesture;
                        if (keyGesture != null) 
                        {
                            return keyGesture.GetDisplayStringForCulture(CultureInfo.CurrentCulture); 
                        } 
                    }
                } 
            }

            return value;
        } 

        ///  
        ///     The DependencyProperty for the Icon property. 
        ///     Default Value:      null
        ///  
        public static readonly DependencyProperty IconProperty =
                DependencyProperty.Register(
                        "Icon",
                        typeof(object), 
                        typeof(MenuItem),
                        new FrameworkPropertyMetadata((object)null)); 
 
        /// 
        ///     Text describing an input gesture that will invoke the command tied to this item. 
        /// 
        [Bindable(true), CustomCategory("Content")]
        public object Icon
        { 
            get { return GetValue(IconProperty); }
            set { SetValue(IconProperty, value); } 
        } 

        // This is used to disable animations after the menu has displayed once 
        private static readonly DependencyPropertyKey IsSuspendingPopupAnimationPropertyKey
            = DependencyProperty.RegisterReadOnly("IsSuspendingPopupAnimation", typeof(bool), typeof(MenuItem),
                                          new FrameworkPropertyMetadata(BooleanBoxes.FalseBox));
 
        /// 
        /// Returns true if the Menu should suspend animations on its popup 
        ///  
        public static readonly DependencyProperty IsSuspendingPopupAnimationProperty = IsSuspendingPopupAnimationPropertyKey.DependencyProperty;
 
        /// 
        /// Returns true if the Menu should suspend animations on its popup
        /// 
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] 
        public bool IsSuspendingPopupAnimation
        { 
            get 
            {
                return (bool)GetValue(IsSuspendingPopupAnimationProperty); 
            }
            internal set
            {
                SetValue(IsSuspendingPopupAnimationPropertyKey, BooleanBoxes.Box(value)); 
            }
        } 
 
        // When opening the menu item, tell all other menu items at the same
        // level that their submenus should not animate 
        private void NotifySiblingsToSuspendAnimation()
        {
            // Don't need to set this property if it is already false
            if (!IsSuspendingPopupAnimation) 
            {
                bool openedWithKeyboard = MenuItem.GetBoolField(this, BoolField.OpenedWithKeyboard); 
 
                // When opened by the keyboard, don't animate - set menumode on all items
                // otherwise ignore this MenuItem so it animates when opening 
                MenuItem ignore = openedWithKeyboard ? null : this;

                ItemsControl parent = ItemsControl.ItemsControlFromItemContainer(this);
                MenuBase.SetSuspendingPopupAnimation(parent, ignore, true); 

                if (!openedWithKeyboard) 
                { 
                    // Delay setting InMenuMode on this until after bindings have done their
                    // work and opened the popup (if it exists) 
                    Dispatcher.BeginInvoke(DispatcherPriority.Input,
                            (DispatcherOperationCallback)delegate(object arg)
                            {
                                ((MenuItem)arg).IsSuspendingPopupAnimation = true; 
                                return null;
                            }, 
                            this); 
                }
                else 
                {
                    MenuItem.SetBoolField(this, BoolField.OpenedWithKeyboard, false);
                }
            } 
        }
 
        // Set IsSuspendingAnimation=false on all our children 
        private void NotifyChildrenToResumeAnimation()
        { 
            MenuBase.SetSuspendingPopupAnimation(this, null, false);
        }

        #endregion 

        //------------------------------------------------------------------- 
        // 
        //  Protected Methods
        // 
        //-------------------------------------------------------------------

        #region Protected Methods
 
        /// 
        /// Creates AutomationPeer () 
        ///  
        protected override System.Windows.Automation.Peers.AutomationPeer OnCreateAutomationPeer()
        { 
            return new System.Windows.Automation.Peers.MenuItemAutomationPeer(this);
        }

        ///  
        ///     This virtual method in called when IsInitialized is set to true and it raises an Initialized event
        ///  
        protected override void OnInitialized(EventArgs e) 
        {
            base.OnInitialized(e); 
            UpdateRole();
#if OLD_AUTOMATION
            CoerceValue(AutomationProvider.AcceleratorKeyProperty);
#endif 
        }
 
        ///  
        /// 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); 
        } 

        ///  
        ///     Automatically set the Command property if the data item that this MenuItem represents is a command.
        /// 
        internal static void PrepareMenuItem(DependencyObject element, object item)
        { 
            MenuItem menuItem = element as MenuItem;
            if (menuItem != null) 
            { 
                ICommand command = item as ICommand;
                if (command != null) 
                {
                    if (!menuItem.HasNonDefaultValue(CommandProperty))
                    {
                        menuItem.Command = command; 
                    }
                } 
 
                if (MenuItem.GetBoolField(menuItem, BoolField.CanExecuteInvalid))
                { 
                    menuItem.UpdateCanExecute();
                }
            }
            else 
            {
                Separator separator = item as Separator; 
                if (separator != null) 
                {
                    bool hasModifiers; 
                    BaseValueSourceInternal vs = separator.GetValueSource(StyleProperty, null, out hasModifiers);
                    if (vs <= BaseValueSourceInternal.ImplicitReference)
                        separator.SetResourceReference(StyleProperty, SeparatorStyleKey);
 
                    separator.DefaultStyleKey = SeparatorStyleKey;
                } 
            } 

        } 

        /// 
        /// This virtual method in called when the MenuItem is clicked and it raises a Click event
        ///  
        /// 
        /// Critical - Calls OnClickImple which sets the userInitiated bit on a command, which is used 
        ///            for security purposes later. 
        /// TreatAsSafe - passes false for userInitiated
        ///  
        [SecurityCritical, SecurityTreatAsSafe]
        protected virtual void OnClick()
        {
            OnClickImpl(false); 
        }
 
        ///  
        /// Critical - accepts a parameter which may be used to set the userInitiated
        ///             bit on a command, which is used for security purposes later. 
        /// 
        [SecurityCritical]
        internal virtual void OnClickCore(bool userInitiated)
        { 
            OnClick();
        } 
 
        /// 
        /// Critical - Calls InvokeClickAfterRender which sets the userInitiated 
        ///             bit on a command, which is used for security purposes later.
        /// 
        [SecurityCritical]
        internal void OnClickImpl(bool userInitiated) 
        {
            if (IsCheckable) 
            { 
                SetCurrentValueInternal(IsCheckedProperty, BooleanBoxes.Box(!IsChecked));
            } 
            // Sub menu items will always be focused if they are moused over or keyboard navigated onto.
            // When you click on a top-level menu item it should take focus.
            // Sub menu items will not be focused if the mouse has moved out of
            // the active hierarchy and has not settled on a new hierarchy yet. 
            if (!IsKeyboardFocusWithin)
            { 
                FocusOrSelect(); 
            }
 
            // Raise the preview click.  This will be handled by the parent menu and cause this submenu to disappear.
            // It will also block until render-priority queue items have completed.
            RaiseEvent(new RoutedEventArgs(MenuItem.PreviewClickEvent, this));
 
            // Raise the automation event first *before* raising the Click event -
            // otherwise automation may not get the event until after raising the click 
            // event returns, which could be problematic if the handler for that event 
            // displayed a modal dialog or did other significant work.
            if (AutomationPeer.ListenerExists(AutomationEvents.InvokePatternOnInvoked)) 
            {
                AutomationPeer peer = UIElementAutomationPeer.CreatePeerForElement(this);
                if (peer != null)
                    peer.RaiseAutomationEvent(AutomationEvents.InvokePatternOnInvoked); 
            }
 
            // We have just caused all the popup windows to be hidden and queued for async 
            // destroy (at < render priority).  Hiding the window will cause the underlying windows
            // to be queued for repaint -- we need to wait for any windows in our context to repaint. 
            Dispatcher.BeginInvoke(DispatcherPriority.Render, new DispatcherOperationCallback(InvokeClickAfterRender), userInitiated);
        }

        ///  
        /// Critical - sets the userInitiated bit on a command, which is used
        ///            for security purposes later. 
        ///  
        [SecurityCritical]
        private object InvokeClickAfterRender(object arg) 
        {
            bool userInitiated = (bool)arg;
            RaiseEvent(new RoutedEventArgs(MenuItem.ClickEvent, this));
            MS.Internal.Commands.CommandHelpers.CriticalExecuteCommandSource(this, userInitiated); 
            return null;
        } 
 

        ///  
        ///        Called when the left mouse button is pressed.
        /// 
        /// 
        ///  
        ///     Critical: Sets an internal variable in case input was user initiated and button was pressed
        ///     TreatAsSafe: The variable is not exposed and there is a demand for UserInitiatedRoutedEvent permission 
        ///                 before setting the variable 
        /// 
        [SecurityCritical,SecurityTreatAsSafe] 
        protected override void OnMouseLeftButtonDown(MouseButtonEventArgs e)
        {
            if (!e.Handled)
            { 
                HandleMouseDown(e);
                UpdateIsPressed(); 
                if (e.UserInitiated) 
                {
                    _userInitiatedPress = true; 
                }
            }
            base.OnMouseLeftButtonDown(e);
        } 

 
        ///  
        ///        Called when the right mouse button is pressed.
        ///  
        /// 
        /// 
        ///     Critical: Sets an internal variable in case input was user initiated and button was pressed
        ///     TreatAsSafe: The variable is not exposed and there is a demand for UserInitiatedRoutedEvent permission 
        ///                 before setting the variable
        ///  
        [SecurityCritical,SecurityTreatAsSafe] 
        protected override void OnMouseRightButtonDown(MouseButtonEventArgs e)
        { 
            if (!e.Handled)
            {
                HandleMouseDown(e);
                if (e.UserInitiated) 
                {
                    _userInitiatedPress = true; 
                } 
            }
            base.OnMouseRightButtonDown(e); 
        }

        /// 
        ///        Called when the left mouse button is released. 
        /// 
        ///  
        ///  
        /// Critical - sets _userInitiatedPress
        /// TreatAsSafe - setting this to false is safe 
        /// 
        [SecurityCritical,SecurityTreatAsSafe]
        protected override void OnMouseLeftButtonUp(MouseButtonEventArgs e)
        { 
            if (!e.Handled)
            { 
                HandleMouseUp(e); 
                UpdateIsPressed();
                _userInitiatedPress = false; 
            }
            base.OnMouseLeftButtonUp(e);
        }
 
        /// 
        ///        Called when the right mouse button is released. 
        ///  
        /// 
        ///  
        /// Critical - sets _userInitiatedPress
        /// TreatAsSafe - setting this to false is safe
        /// 
        [SecurityCritical,SecurityTreatAsSafe] 
        protected override void OnMouseRightButtonUp(MouseButtonEventArgs e)
        { 
            if (!e.Handled) 
            {
                HandleMouseUp(e); 
                _userInitiatedPress = false;
            }
            base.OnMouseRightButtonUp(e);
        } 

        private void HandleMouseDown(MouseButtonEventArgs e) 
        { 
            // ((0, 0), RenderSize) is the closest we can get to checking if the
            // mouse event was on the header portion of the MenuItem (i.e. not on 
            // any part of the submenu)
            Rect r = new Rect(new Point(), RenderSize);

            if (r.Contains(e.GetPosition(this))) 
            {
                if (e.ChangedButton == MouseButton.Left || (e.ChangedButton == MouseButton.Right && InsideContextMenu)) 
                { 
                    // Click happens on down for headers
                    MenuItemRole role = Role; 

                    if (role == MenuItemRole.TopLevelHeader || role == MenuItemRole.SubmenuHeader)
                    {
                        ClickHeader(); 
                    }
                } 
            } 
            // Handle mouse messages b/c they were over me, I just didn't use it
            e.Handled = true; 
        }

        /// 
        /// Critical - Calls ClickItem, setting the userInitiated 
        ///             bit, which is used for security purposes later.
        /// TreatAsSafe - e.UserInitiated can always be trusted 
        ///  
        [SecurityCritical,SecurityTreatAsSafe]
        private void HandleMouseUp(MouseButtonEventArgs e) 
        {
            // See comment above in HandleMouseDown.
            Rect r = new Rect(new Point(), RenderSize);
 
            if (r.Contains(e.GetPosition(this)))
            { 
                if (e.ChangedButton == MouseButton.Left || (e.ChangedButton == MouseButton.Right && InsideContextMenu)) 
                {
                    // Click happens on up for items 
                    MenuItemRole role = Role;

                    if (role == MenuItemRole.TopLevelItem || role == MenuItemRole.SubmenuItem)
                    { 
                        if (_userInitiatedPress == true)
                        { 
                            ClickItem(e.UserInitiated); 
                        }
                        else 
                        {
                            // This is the case where the mouse down happend on a different element
                            // but the moust up is happening on the menuitem. this is to prevent spoofing
                            // attacks where someone substitutes an element with a menu item 
                            ClickItem(false);
                        } 
                    } 

                    // 
                    /*
                    // Click happens on up for top level items that are already open
                    if (role == MenuItemRole.TopLevelHeader && IsSubmenuOpen)
                    { 
                        ClickHeader();
                        e.Handled = true; 
                    } 
                    */
                } 
            }

            if (e.ChangedButton != MouseButton.Right || InsideContextMenu)
            { 
                // Handle all clicks unless there's a possibility of a ContextMenu inside a Menu.
                e.Handled = true; 
            } 
        }
 
        private static void OnAccessKeyPressed(object sender, AccessKeyPressedEventArgs e)
        {
            MenuItem menuItem = sender as MenuItem;
            bool isScope = false; 

            if (e.Target == null) 
            { 
                // MenuItem access key should not work if something else beside MenuBase has capture
                if (Mouse.Captured == null || Mouse.Captured is MenuBase) 
                {
                    e.Target = menuItem;

                    // special case is if we are the original source and our submenu is open, 
                    // this is the case where the mouse moved over the header and focus is on
                    // the menu item but really you want to access key processing to be in your 
                    // submenu. 
                    // This assumes that no one will ever directly register a MenuItem with the AKM.
                    if (e.OriginalSource == menuItem && menuItem.IsSubmenuOpen) 
                    {
                        isScope = true;
                    }
                } 
                else
                { 
                    e.Handled = true; 
                }
            } 
            else if (e.Scope == null)
            {
                // We want menu items to be a scope, but not for any AKs in its header.
 
                // If e.Target is already filled in, check if it's a MenuItem.
                // If it is and it's not us, we are its scope (i.e. we're the first MenuItem 
                // above it in the chain).  If it's not a MenuItem, we have to take the long way. 
                if (e.Target != menuItem && e.Target is MenuItem)
                { 
                    isScope = true;
                }
                else
                { 
                    // This case handles when you have some non-MenuItem in a menu that can be
                    // the target of access keys, like a Button. 
 
                    // MenuItems are a scope for all access keys which are outside of themselves.
                    // e.Source is the logical element in which the event was raised. 
                    // If we can walk from the source to ourselves, then we are not correct
                    // scope of this access key; some parent should be.

                    DependencyObject source = e.Source as DependencyObject; 

                    while (source != null) 
                    { 
                        // If we walk up to this Menuitem, we are not the scope.
                        if (source == menuItem) 
                        {
                            break;
                        }
 
                        UIElement uiElement = source as UIElement;
 
                        // If we walk up to an item which is one of our children, we are their scope. 
                        if ((uiElement != null) && (ItemsControlFromItemContainer(uiElement) == menuItem))
                        { 
                            isScope = true;
                            break;
                        }
 
                        source = GetFrameworkParent(source);
                    } 
                } 
            }
 
            if (isScope)
            {
                e.Scope = menuItem;
                e.Handled = true; 
            }
        } 
 
        /// 
        ///     An event reporting the mouse entered or left this element. 
        /// 
        protected override void OnMouseLeave(MouseEventArgs  e)
        {
            base.OnMouseLeave(e); 

            MenuItemRole role = Role; 
 
            // When we're a top-level menuitem we have to check if the menu has capture.
            // If it doesn't we fall to the else below where we are just mousing around 
            // the top-level menuitems.
            // (Note that Submenu items/headers do not have to look for capture.)
            if (((role == MenuItemRole.TopLevelHeader || role == MenuItemRole.TopLevelItem) && IsInMenuMode)
                || (role == MenuItemRole.SubmenuHeader || role == MenuItemRole.SubmenuItem)) 
            {
                MouseLeaveInMenuMode(role); 
            } 
            else
            { 
                // Here we don't have capture and we're just mousing over
                // top-level menu items.  IsSelected should correspond to IsMouseOver.
                if (IsMouseOver != IsSelected)
                { 
                    SetCurrentValueInternal(IsSelectedProperty, BooleanBoxes.Box(IsMouseOver));
                } 
            } 

            UpdateIsPressed(); 
        }

        /// 
        /// This is the method that responds to the MouseEvent event. 
        /// 
        protected override void OnMouseMove(MouseEventArgs e) 
        { 
            // Ignore any mouse moves on ourselves while the popup is opening.
            MenuItem parent = ItemsControl.ItemsControlFromItemContainer(this) as MenuItem; 
            if (parent != null &&
                MenuItem.GetBoolField(parent, BoolField.MouseEnterOnMouseMove))
            {
                MenuItem.SetBoolField(parent, BoolField.MouseEnterOnMouseMove, false); 
                MouseEnterHelper();
            } 
        } 

        ///  
        ///     An event reporting the mouse entered or left this element.
        /// 
        protected override void OnMouseEnter(MouseEventArgs  e)
        { 
            base.OnMouseEnter(e);
            MouseEnterHelper(); 
        } 

        private void MouseEnterHelper() 
        {
            ItemsControl parent = ItemsControl.ItemsControlFromItemContainer(this);
            // Do not enter and highlight this item until the popup has opened
            // This prevents immediately selecting a submenu item when opening the menu 
            // because the mouse was already where the menu item appeared
            if (parent == null || !MenuItem.GetBoolField(parent, BoolField.IgnoreMouseEvents)) 
            { 
                MenuItemRole role = Role;
 
                // When we're a top-level menuitem we have to check if the menu has capture.
                // If it doesn't we fall to the else below where we are just mousing around
                // the top-level menuitems.
                // (Note that Submenu items/headers do not have to look for capture.) 
                if (((role == MenuItemRole.TopLevelHeader || role == MenuItemRole.TopLevelItem) && OpenOnMouseEnter)
                    || (role == MenuItemRole.SubmenuHeader || role == MenuItemRole.SubmenuItem)) 
                { 
                    MouseEnterInMenuMode(role);
                } 
                else
                {
                    // Here we don't have capture and we're just mousing over
                    // top-level menu items.  IsSelected should correspond to IsMouseOver. 
                    if (IsMouseOver != IsSelected)
                    { 
                        SetCurrentValueInternal(IsSelectedProperty, BooleanBoxes.Box(IsMouseOver)); 
                    }
                } 

                UpdateIsPressed();
            }
            else if (parent is MenuItem) 
            {
                MenuItem.SetBoolField(parent, BoolField.MouseEnterOnMouseMove, true); 
            } 
        }
 
        private void MouseEnterInMenuMode(MenuItemRole role)
        {
            switch (role)
            { 
                case MenuItemRole.TopLevelHeader:
                case MenuItemRole.TopLevelItem: 
                    { 
                        // When mousing over a top-level hierarchy, it should open immediately.
                        if (!IsSubmenuOpen) 
                        {
                            OpenHierarchy(role);
                        }
                    } 
                    break;
 
                case MenuItemRole.SubmenuHeader: 
                case MenuItemRole.SubmenuItem:
                    { 
                        // If the current sibling has an open hierarchy, we cannot
                        // move focus/selection immediately.  Instead we must set
                        // a timer to open after MenuShowDelay ms.  If the sibling has
                        // no hierarchy open, it is safe to select the item immediately. 
                        MenuItem sibling = CurrentSibling;
 
                        if (sibling == null || !sibling.IsSubmenuOpen) 
                        {
                            if (!IsSubmenuOpen) 
                            {
                                // Try to focus/select this item.
                                FocusOrSelect();
                            } 
                            else
                            { 
                                // If the submenu is open, then it should already be selected. 
                                Debug.Assert(IsSelected, "When IsSubmenuOpen = true, IsSelected should be true as well");
 
                                // Need to make sure that when we leave the hierarchy and come back
                                // that the item is highlighted.
                                IsHighlighted = true;
                            } 
                        }
                        else 
                        { 
                            // Highlight this item and remove the highlight
                            // from its sibling selected MenuItem 
                            sibling.IsHighlighted = false;
                            IsHighlighted = true;
                        }
 
                        // If the submenu isn't open already, OpenHierarchy after MenuShowDelay ms
                        if (!IsSelected || !IsSubmenuOpen) 
                        { 
                            // When the timout happens, OpenHierarchy will select this item
                            SetTimerToOpenHierarchy(); 
                        }
                    }
                    break;
            } 

 
            // Now that we're over this menu hierarchy with the mouse, we 
            // should stop any timers which might cause this hierarchy to close.
            StopTimer(ref _closeHierarchyTimer); 
        }

        private void MouseLeaveInMenuMode(MenuItemRole role)
        { 
            // When mouse moves out of a submenu item, we should deselect
            // the item.  This is what Win32 does, and our menus don't 
            // feel right without it. 
            if (role == MenuItemRole.SubmenuHeader || role == MenuItemRole.SubmenuItem)
            { 
                if (MenuItem.GetBoolField(this, BoolField.IgnoreNextMouseLeave))
                {
                    // The mouse was within a submenu that closed. A submenu header is receiving this
                    // message, but we want to ignore this one. 
                    MenuItem.SetBoolField(this, BoolField.IgnoreNextMouseLeave, false);
                } 
                else 
                {
                    if (!IsSubmenuOpen) 
                    {
                        // When the submenu isn't open we can deselect the item right away.
                        if (IsSelected)
                        { 
                            SetCurrentValueInternal(IsSelectedProperty, BooleanBoxes.FalseBox);
                        } 
                        else 
                        {
                            // If it's not selected it might just be highlighted, 
                            // so remove the highlight.
                            IsHighlighted = false;
                        }
 
                        if (IsKeyboardFocusWithin)
                        { 
                            ItemsControl parent = ItemsControl.ItemsControlFromItemContainer(this); 
                            if (parent != null)
                            { 
                                parent.Focus();
                            }
                        }
                    } 
                    else
                    { 
                        // If the submenu is open and the mouse moved to some sibling 
                        // hierarchy, we need to delay and deselect the item after
                        // MenuShowDelay ms, as long as the item doesn't get re-selected. 
                        if (IsMouseOverSibling)
                        {
                            SetTimerToCloseHierarchy();
                        } 
                    }
                } 
            } 

            // No matter what, we've left the menu item and we should 
            // stop any timer which would cause the item to open.
            StopTimer(ref _openHierarchyTimer);
        }
 
        /// 
        ///     An event announcing that the keyboard is focused on this element. 
        ///  
        protected override void OnGotKeyboardFocus(KeyboardFocusChangedEventArgs e)
        { 
            base.OnGotKeyboardFocus(e);

            // Focus drives selection.  If a MenuItem is focused, it should
            // select itself. 
            if (!e.Handled && e.NewFocus == this)
            { 
                SetCurrentValueInternal(IsSelectedProperty, BooleanBoxes.TrueBox); 
            }
        } 

        /// 
        /// Called when the focus is no longer on or within this element.
        ///  
        protected override void OnIsKeyboardFocusWithinChanged(DependencyPropertyChangedEventArgs e)
        { 
            base.OnIsKeyboardFocusWithinChanged(e); 

            if (IsKeyboardFocusWithin && !IsSelected) 
            {
                // If an item within us got focus (probably programatically), we need to become selected
                SetCurrentValueInternal(IsSelectedProperty, BooleanBoxes.TrueBox);
            } 
        }
 
        ///  
        ///     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
        /// 
        /// Critical - Calls ClickItem, setting the userInitiated
        ///             bit, which is used for security purposes later. 
        /// PublicOK - e.UserInitiated can always be trusted
        ///  
        [SecurityCritical] 
        protected override void OnKeyDown(KeyEventArgs e)
        { 
            base.OnKeyDown(e);

            bool handled = false;
 
            Key key = e.Key;
            MenuItemRole role = Role; 
            FlowDirection flowDirection = FlowDirection; 

            // In Right to Left mode we switch Right and Left keys 
            if (flowDirection == FlowDirection.RightToLeft)
            {
                if (key == Key.Right)
                { 
                    key = Key.Left;
                } 
                else if (key == Key.Left) 
                {
                    key = Key.Right; 
                }
            }

            switch (key) 
            {
                case Key.Tab: 
                    if (role == MenuItemRole.SubmenuHeader && IsSubmenuOpen && CurrentSelection == null) 
                    {
                        if ((Keyboard.Modifiers & ModifierKeys.Shift) == ModifierKeys.Shift) 
                        {
                            NavigateToEnd(new ItemNavigateArgs(e.Device, Keyboard.Modifiers));
                        }
                        else 
                        {
                            NavigateToStart(new ItemNavigateArgs(e.Device, Keyboard.Modifiers)); 
                        } 

                        handled = true; 
                    }
                    break;

                case Key.Right: 
                    if ((role == MenuItemRole.SubmenuHeader) && !IsSubmenuOpen)
                    { 
                        OpenSubmenuWithKeyboard(); 
                        handled = true;
                    } 
                    break;

                case Key.Enter:
                    { 
                        if (((role == MenuItemRole.SubmenuItem) || (role == MenuItemRole.TopLevelItem)))
                        { 
                            Debug.Assert(IsHighlighted, "MenuItem got Key.Enter but was not highlighted -- focus did not follow highlight?"); 
                            ClickItem(e.UserInitiated);
                            handled = true; 
                        }
                        else if (role == MenuItemRole.TopLevelHeader)
                        {
                            // 
                            OpenSubmenuWithKeyboard();
                            handled = true; 
                        } 
                        else if (role == MenuItemRole.SubmenuHeader && !IsSubmenuOpen)
                        { 
                            OpenSubmenuWithKeyboard();
                            handled = true;
                        }
                    } 
                    break;
 
                // If a menuitem gets a down or up key and the submenu is open, we should focus the first or last 
                // item in the submenu (respectively).  If the submenu is not opened, this will be handled by Menu.
                case Key.Down: 
                    {
                        if (role == MenuItemRole.SubmenuHeader && IsSubmenuOpen && CurrentSelection == null)
                        {
                            NavigateToStart(new ItemNavigateArgs(e.Device, Keyboard.Modifiers)); 
                            handled = true;
                        } 
                    } 
                    break;
 
                case Key.Up:
                    {
                        if (role == MenuItemRole.SubmenuHeader && IsSubmenuOpen && CurrentSelection == null)
                        { 
                            NavigateToEnd(new ItemNavigateArgs(e.Device, Keyboard.Modifiers));
                            handled = true; 
                        } 
                    }
                    break; 

                case Key.Left:
                case Key.Escape:
                    { 
                        // If Left or Escape is pressed on a Submenu Item or Header, the submenu should be closed.
                        // Closing the submenu will move focus out of the submenu and onto the parent MenuItem. 
                        if ((role != MenuItemRole.TopLevelHeader) && (role != MenuItemRole.TopLevelItem)) 
                        {
                            if (IsSubmenuOpen) 
                            {
                                SetCurrentValueInternal(IsSubmenuOpenProperty, BooleanBoxes.FalseBox);
                                handled = true;
                            } 
                        }
                    } 
                    break; 
            }
 

            if (!handled)
            {
                ItemsControl parent = ItemsControl.ItemsControlFromItemContainer(this); 
                /*
                 * This sets the ignore flag and adds a dispatcher that will run after all rendering has completed. 
                 * parent can be null when this is in the visual tree but not in an ItemsList.  Not recomended but still possible. 
                 * The IgnoreFlag could be set if multiple KeyPresses happen before the key ups.  There only needs to be one dispatcher
                 * on the queue. 
                 * */
                if ((parent != null) && (!MenuItem.GetBoolField(parent, BoolField.IgnoreMouseEvents)))
                {
                    //Ignore Mouse Events 
                    MenuItem.SetBoolField(parent, BoolField.IgnoreMouseEvents, true);
 
                    // MenuItem should ignore any mouse enter or move events until the menu has fully 
                    // moved.  So this is added to the Dispatcher with Background
                    parent.Dispatcher.BeginInvoke(DispatcherPriority.Background, new DispatcherOperationCallback(delegate(object param) 
                    {
                        MenuItem.SetBoolField(parent, BoolField.IgnoreMouseEvents, false);
                        return null;
                    }), null); 
                }
 
                // Use the unadulterated e.Key here because the later translation 
                // to FocusNavigationDirection takes this into account.
                handled = MenuItemNavigate(e.Key, e.KeyboardDevice.Modifiers); 
            }

            if (handled)
            { 
                e.Handled = true;
            } 
        } 

        ///  
        /// The Access key for this control was invoked.
        /// 
        /// 
        /// Critical - Calls ClickItem, setting the userInitiated 
        ///             bit, which is used for security purposes later.
        /// PublicOK - e.UserInitiated can always be trusted 
        ///  
        [SecurityCritical]
        protected override void OnAccessKey(AccessKeyEventArgs e) 
        {
            base.OnAccessKey(e);

            if (!e.IsMultiple) 
            {
                MenuItemRole type = Role; 
 
                switch (type)
                { 
                    case MenuItemRole.TopLevelItem:
                    case MenuItemRole.SubmenuItem:
                        {
                            ClickItem(e.UserInitiated); 
                        }
                        break; 
 
                    case MenuItemRole.TopLevelHeader :
                    case MenuItemRole.SubmenuHeader : 
                        {
                            OpenSubmenuWithKeyboard();
                        }
                        break; 
                }
            } 
        } 

        ///  
        ///     This method is invoked when the Items property changes.
        /// 
        protected override void OnItemsChanged(NotifyCollectionChangedEventArgs e)
        { 
            // We use visual triggers to place the popup based on RoleProperty.
            // Update the RoleProperty when Items property changes so popup can be placed accordingly. 
            UpdateRole(); 
            base.OnItemsChanged(e);
        } 

        /// 
        /// Return true if the item is (or is eligible to be) its own ItemUI
        ///  
        protected override bool IsItemItsOwnContainerOverride(object item)
        { 
            return (item is MenuItem) || (item is Separator); 
        }
 
        /// 
        /// Determine whether the ItemContainerStyle/StyleSelector should apply to the item or not
        /// 
        protected override bool ShouldApplyItemContainerStyle(DependencyObject container, object item) 
        {
            if (item is Separator) 
            { 
                return false;
            } 
            else
            {
                return base.ShouldApplyItemContainerStyle(container, item);
            } 
        }
 
 

        ///  Create or identify the element used to display the given item.  
        protected override DependencyObject GetContainerForItemOverride()
        {
            return new MenuItem();
        } 

        ///  
        ///     Called when the parent of the Visual has changed. 
        /// 
        /// Old parent or null if the Visual did not have a parent before. 
        protected internal override void OnVisualParentChanged(DependencyObject oldParent)
        {
            base.OnVisualParentChanged(oldParent);
            UpdateRole(); 

            // Windows OS bug:1988393; DevDiv bug:107459 
            // MenuItem template contains ItemsPresenter where Grid.IsSharedSizeScope="true" and need to inherits PrivateSharedSizeScopeProperty value 
            // Property inheritance walk the locial tree if possible and skip the visual tree where ItemsPresenter is
            // Workaround here will be to copy the property value from MenuItem visual parent 

            DependencyObject newParent = VisualTreeHelper.GetParentInternal(this);

            // logical parent != null 
            // visual parent != null
            // logical parent != visual parent <-- we are in the MenuItem is a logical child of a MenuItem case, not a data container case 
            // --- Set one-way binding with visual parent for DefinitionBase.PrivateSharedSizeScopeProperty 
            // NOTE: It seems impossible to get shared size scope to work in this hierarchical scenario
            // under normal conditions, so putting this binding here without respecting an author's desire for 
            // shared size scope on the MenuItem container should be OK, since they wouldn't be able to
            // get it to work anyway.
            if (Parent != null && newParent != null && Parent != newParent)
            { 
                Binding binding = new Binding();
                binding.Path = new PropertyPath(DefinitionBase.PrivateSharedSizeScopeProperty); 
                binding.Mode = BindingMode.OneWay; 
                binding.Source = newParent;
                BindingOperations.SetBinding(this, DefinitionBase.PrivateSharedSizeScopeProperty, binding); 
            }

            // visual parent == null
            // --- Clear binding for DefinitionBase.PrivateSharedSizeScopeProperty 
            if (newParent == null)
            { 
                BindingOperations.ClearBinding(this, DefinitionBase.PrivateSharedSizeScopeProperty); 
            }
 
        }

        /// 
        /// Called when the Template's tree has been generated 
        /// 
        public override void OnApplyTemplate() 
        { 
            base.OnApplyTemplate();
 
            if (_submenuPopup != null)
            {
                _submenuPopup.Closed -= OnPopupClosed;
            } 

            _submenuPopup = GetTemplateChild(PopupTemplateName) as Popup; 
 
            if (_submenuPopup != null)
            { 
                _submenuPopup.Closed += OnPopupClosed;
            }
        }
 
        #endregion
 
        //------------------------------------------------------------------- 
        //
        //  Private Methods 
        //
        //--------------------------------------------------------------------

        #region Private Methods 

        private void SetMenuMode(bool menuMode) 
        { 
            Debug.Assert(Role == MenuItemRole.TopLevelHeader || Role == MenuItemRole.TopLevelItem, "MenuItem was not top-level");
 
            MenuBase parentMenu = LogicalParent as MenuBase;

            if (parentMenu != null)
            { 
                if (parentMenu.IsMenuMode != menuMode)
                { 
                    parentMenu.IsMenuMode = menuMode; 
                }
            } 
        }

        /// 
        /// Returns true if the parent has capture.  Does not work for submenu items/headers. 
        /// 
        private bool IsInMenuMode 
        { 
            get
            { 
                MenuBase parentMenu = LogicalParent as MenuBase;
                if (parentMenu != null)
                {
                    return parentMenu.IsMenuMode; 
                }
 
                return false; 
            }
        } 

        /// 
        /// Returns true if the top level header should open when the mouse enters it
        ///  
        private bool OpenOnMouseEnter
        { 
            get 
            {
                MenuBase parentMenu = LogicalParent as MenuBase; 
                if (parentMenu != null)
                {
                    Debug.Assert(!parentMenu.OpenOnMouseEnter || parentMenu.IsMenuMode, "OpenOnMouseEnter can only be true when IsMenuMode is true");
                    return parentMenu.OpenOnMouseEnter; 
                }
 
                return false; 
            }
        } 

        // This is so that MenuItems inside a ContextMenu can behave differently
        internal static readonly DependencyProperty InsideContextMenuProperty
            = DependencyProperty.RegisterAttached("InsideContextMenu", typeof(bool), typeof(MenuItem), 
                                          new FrameworkPropertyMetadata(BooleanBoxes.FalseBox, FrameworkPropertyMetadataOptions.Inherits));
 
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] 
        private bool InsideContextMenu
        { 
            get
            {
                return (bool)GetValue(InsideContextMenuProperty);
            } 
        }
 
        internal static void SetInsideContextMenuProperty(UIElement element, bool value) 
        {
            element.SetValue(InsideContextMenuProperty, BooleanBoxes.Box(value)); 
        }


 
        /// 
        /// Critical - Calls ClickItem, setting the userInitiated 
        ///             bit, which is used for security purposes later. 
        /// TreatAsSafe - passes false.
        ///  
        [SecurityCritical, SecurityTreatAsSafe]
        internal void ClickItem()
        {
            ClickItem(false); 
        }
        ///  
        /// Critical - Calls OnClickCore, setting the userInitiated 
        ///             bit, which is used for security purposes later.
        ///  
        [SecurityCritical]
        private void ClickItem(bool userInitiated)
        {
            try 
            {
                OnClickCore(userInitiated); 
            } 
            finally
            { 
                // When you click a top-level item, we need to exit menu mode.
                if (Role == MenuItemRole.TopLevelItem)
                {
                    SetMenuMode(false); 
                }
            } 
        } 

        internal void ClickHeader() 
        {
            if (!IsKeyboardFocusWithin)
            {
                FocusOrSelect(); 
            }
 
            if (IsSubmenuOpen) 
            {
                if (Role == MenuItemRole.TopLevelHeader) 
                {
                    SetMenuMode(false);
                }
            } 
            else
            { 
                // Immediately open the menu when it's clicked. This will stop any 
                // timers to open or close the submenu.
                OpenMenu(); 
            }
        }

        internal bool OpenMenu() 
        {
            if (!IsSubmenuOpen) 
            { 
                // Verify that the parent of the MenuItem is valid;
                ItemsControl owner = ItemsControl.ItemsControlFromItemContainer(this); 
                if (owner == null)
                {
                    owner = VisualTreeHelper.GetParent(this) as ItemsControl;
                } 

                if ((owner != null) && ((owner is MenuItem) || (owner is MenuBase))) 
                { 
                    // Parent must be MenuItem or MenuBase in order for menus to open.
                    // Otherwise, odd behavior will occur. 
                    SetCurrentValueInternal(IsSubmenuOpenProperty, BooleanBoxes.TrueBox);
                    return true; // The value was actually changed
                }
            } 

            return false; 
        } 

        ///  
        ///     Set IsSubmenuOpen = true and select the first item.
        /// 
        internal void OpenSubmenuWithKeyboard()
        { 
            MenuItem.SetBoolField(this, BoolField.OpenedWithKeyboard, true);
            if (OpenMenu()) 
            { 
                NavigateToStart(new ItemNavigateArgs(Keyboard.PrimaryDevice, Keyboard.Modifiers));
            } 
        }

        /// 
        /// Navigate from one MenuItem to a sibling. 
        /// 
        /// Raw key that was pressed (RTL is respected within this method). 
        ///  
        /// true if navigation was successful.
        private bool MenuItemNavigate(Key key, ModifierKeys modifiers) 
        {
            if (key == Key.Left || key == Key.Right || key == Key.Up || key == Key.Down)
            {
                ItemsControl parent = ItemsControlFromItemContainer(this); 
                if (parent != null)
                { 
                    if (!parent.HasItems) 
                    {
                        return false; 
                    }

                    int count = parent.Items.Count;
 
                    // Optimize for the case where the submenu contains one item.
 
                    if (count == 1 && !(parent is Menu)) 
                    {
                        // Return true if we were navigating up/down (we cycled around). 
                        if (key == Key.Up && key == Key.Down)
                        {
                            return true;
                        } 
                    }
 
                    object previousFocus = Keyboard.FocusedElement; 
                    parent.NavigateByLine(KeyboardNavigation.KeyToTraversalDirection(key), new ItemNavigateArgs(Keyboard.PrimaryDevice, modifiers));
                    object currentFocus = Keyboard.FocusedElement; 
                    if ((currentFocus != previousFocus) && (currentFocus != this))
                    {
                        return true;
                    } 
                }
            } 
 
            return false;
        } 

        /// 
        ///     Returns logical parent; either Parent or ItemsControlFromItemContainer(this).
        ///  
        /// 
        internal object LogicalParent 
        { 
            get
            { 
                if (Parent != null)
                {
                    return Parent;
                } 

                return ItemsControlFromItemContainer(this); 
            } 
        }
 
        /// 
        ///     Return the current sibling of this MenuItem -- the
        ///     CurrentSelection of the parent as long as it isn't us.
        ///  
        private MenuItem CurrentSibling
        { 
            get 
            {
                object parent = LogicalParent; 
                MenuItem menuItemParent = parent as MenuItem;
                MenuItem sibling = null;

                if (menuItemParent != null) 
                {
                    sibling = menuItemParent.CurrentSelection; 
                } 
                else
                { 
                    MenuBase menuParent = parent as MenuBase;

                    if (menuParent != null)
                    { 
                        sibling = menuParent.CurrentSelection;
                    } 
                } 

                if (sibling == this) 
                {
                    sibling = null;
                }
 
                return sibling;
            } 
        } 

        ///  
        ///     Returns true if the mouse is somewhere in the hierarchy
        ///     but not over this node.  Note that this is slightly different
        ///     from CurrentSibling.IsMouseOver because there are regions in
        ///     the menu which are not occupied by siblings and we're interested 
        ///     in that case too.
        ///  
        private bool IsMouseOverSibling 
        {
            get 
            {
                FrameworkElement parent = LogicalParent as FrameworkElement;

                // If the mouse is over our parent but not over us, then 
                // the mouse must be somewhere in a sibling hierarchy.
                // 
                // NOTE: If this check were changed to CurrentSibling.IsMouseOver 
                //       then our behavior becomes identical to the behavior
                //       of the start menu, where a menu doesn't close unless 
                //       you have settled on another hierarchy.  Here we will
                //       close unless you are settled on this item's hierarchy.
                if (parent != null && IsMouseReallyOver(parent) && !IsMouseOver)
                { 
                    return true;
                } 
 
                return false;
            } 
        }

        /// 
        ///     Performs an IsMouseOver test but accounts for elements that have capture 
        ///     and instead checks their children.
        ///  
        /// The element to test. 
        /// True if the mouse is over the element, regardless of capture. False otherwise.
        private static bool IsMouseReallyOver(FrameworkElement elem) 
        {
            bool isMouseOver = elem.IsMouseOver;

            if (isMouseOver) 
            {
                if ((Mouse.Captured == elem) && (Mouse.DirectlyOver == elem)) 
                { 
                    // The mouse is not over any of the children of this captured element.
                    // Assuming that this means that the mouse is not really over the element. 
                    return false;
                }
            }
 
            return isMouseOver;
        } 
 
        /// 
        ///     Select this item and expand the hierarchy below it. 
        /// 
        /// 
        private void OpenHierarchy(MenuItemRole role)
        { 
            FocusOrSelect();
 
            if (role == MenuItemRole.TopLevelHeader || role == MenuItemRole.SubmenuHeader) 
            {
                OpenMenu(); 
            }
        }

        ///  
        ///     Focus this item or, if that fails, just mark it selected.
        ///  
        private void FocusOrSelect() 
        {
            // Setting focus will cause the item to be selected, 
            // but if we fail to focus we should still select.
            // (This is to help enable focusless menus).
            // Check IsKeyboardFocusWithin to allow rich content within the menuitem.
            if (!IsKeyboardFocusWithin) 
            {
                Focus(); 
            } 

            if (!IsSelected) 
            {
                // If it's already focused, make sure it's also selected.
                SetCurrentValueInternal(IsSelectedProperty, BooleanBoxes.TrueBox);
            } 

            // If the item is selected we should ensure that it's highlighted. 
            if (IsSelected && !IsHighlighted) 
            {
                IsHighlighted = true; 
            }
        }

        private void SetTimerToOpenHierarchy() 
        {
            if (_openHierarchyTimer == null) 
            { 
                _openHierarchyTimer = new DispatcherTimer(DispatcherPriority.Normal);
                _openHierarchyTimer.Tick += (EventHandler)delegate(object sender, EventArgs e) 
                {
                    OpenHierarchy(Role);
                    StopTimer(ref _openHierarchyTimer);
                }; 
            }
            else 
            { 
                _openHierarchyTimer.Stop();
            } 

            StartTimer(_openHierarchyTimer);
        }
 
        private void SetTimerToCloseHierarchy()
        { 
            if (_closeHierarchyTimer == null) 
            {
                _closeHierarchyTimer = new DispatcherTimer(DispatcherPriority.Normal); 
                _closeHierarchyTimer.Tick += (EventHandler)delegate(object sender, EventArgs e)
                {
                    // Deselect the item; will remove highlight and collapse hierarchy.
                    SetCurrentValueInternal(IsSelectedProperty, BooleanBoxes.FalseBox); 
                    StopTimer(ref _closeHierarchyTimer);
                }; 
            } 
            else
            { 
                _closeHierarchyTimer.Stop();
            }

            StartTimer(_closeHierarchyTimer); 
        }
 
        private void StopTimer(ref DispatcherTimer timer) 
        {
            if (timer != null) 
            {
                timer.Stop();
                timer = null;
            } 
        }
 
        private void StartTimer(DispatcherTimer timer) 
        {
            Debug.Assert(timer != null, "timer should not be null."); 
            Debug.Assert(!timer.IsEnabled, "timer should not be running.");

            timer.Interval = TimeSpan.FromMilliseconds(SystemParameters.MenuShowDelay);
            timer.Start(); 
        }
 
        private static object OnCoerceAcceleratorKey(DependencyObject d, object value) 
        {
            if (value == null) 
            {
                string inputGestureText = ((MenuItem)d).InputGestureText;
                if (inputGestureText != String.Empty)
                { 
                    value = inputGestureText;
                } 
            } 

            return value; 
        }

        #endregion
 
        //-------------------------------------------------------------------
        // 
        //  Private Fields 
        //
        //-------------------------------------------------------------------- 

        #region Private Fields

        ///  
        ///     Tracks the current selection in the items collection (i.e. submenu)
        ///     of this MenuItem. 
        ///  
        private MenuItem CurrentSelection
        { 
            get
            {
                return _currentSelection;
            } 

            set 
            { 
                if (_currentSelection != null)
                { 
                    _currentSelection.SetCurrentValueInternal(IsSelectedProperty, BooleanBoxes.FalseBox);
                }

                _currentSelection = value; 

                if (_currentSelection != null) 
                { 
                    _currentSelection.SetCurrentValueInternal(IsSelectedProperty, BooleanBoxes.TrueBox);
                } 

                // NOTE: (Win32 disparity) If CurrentSelection changes to null
                //       and the focus was within the old CurrentSelection, we
                //       the parent should take focus back.  In Win32 the "virtual" 
                //       focus was tracked by way of the currently selected guy in
                //       If you were selected but none of your children were, you 
                //       were effectively selected.  It should be relatively easy to 
                //       enable this behavior by checking if IsKeyboardFocusWithin is true
                //       on the previous child and then setting Focus to ourselves 
                //       when _currentSelection becomes null.  We would need to do this
                //       here and in MenuBase.CurrentSelection.
            }
        } 

        private static readonly DependencyProperty BooleanFieldStoreProperty = DependencyProperty.RegisterAttached( 
            "BooleanFieldStore", 
            typeof(BoolField),
            typeof(MenuItem), 
            new FrameworkPropertyMetadata(new BoolField())
            );

        private static bool GetBoolField(UIElement element, BoolField field) 
        {
            return (((BoolField)element.GetValue(BooleanFieldStoreProperty)) & field) != 0; 
        } 

        private static void SetBoolField(UIElement element, BoolField field, bool value) 
        {
            if (value)
            {
                element.SetValue(BooleanFieldStoreProperty, ((BoolField)element.GetValue(BooleanFieldStoreProperty)) | field); 
            }
            else 
            { 
                element.SetValue(BooleanFieldStoreProperty, ((BoolField)element.GetValue(BooleanFieldStoreProperty)) & (~field));
            } 
        }

        [Flags]
        private enum BoolField 
        {
            OpenedWithKeyboard = 0x01, 
            IgnoreNextMouseLeave = 0x02, 
            IgnoreMouseEvents = 0x04,
            MouseEnterOnMouseMove = 0x08, 
            CanExecuteInvalid = 0x10,
        }

        // 
        //  This property
        //  1. Finds the correct initial size for the _effectiveValues store on the current DependencyObject 
        //  2. This is a performance optimization 
        //
        internal override int EffectiveValuesInitialSize 
        {
            get { return 42; }
        }
 
        private bool CanExecute
        { 
            get { return !ReadControlFlag(ControlBoolFlags.CommandDisabled); } 
            set
            { 
                if (value != CanExecute)
                {
                    WriteControlFlag(ControlBoolFlags.CommandDisabled, !value);
                    CoerceValue(IsEnabledProperty); 
                }
            } 
        } 

        private const string PopupTemplateName = "PART_Popup"; 

        private MenuItem _currentSelection;
        private Popup _submenuPopup;
 
        DispatcherTimer _openHierarchyTimer;
        DispatcherTimer _closeHierarchyTimer; 
 
        // This is to hold onto a CanExecuteChanged event handler to respond to changes in a command's CanExecute property
        private static readonly UncommonField CanExecuteChangedHandler = new UncommonField(); 

        /// 
        ///     Critical: Setting this to true indicates that the mouse down was user initiated
        ///  
        [SecurityCritical]
        private bool _userInitiatedPress; 
        #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

        #region ItemsStyleKey 
        /// 
        ///     Resource Key for the SeparatorStyle 
        ///  
        public static ResourceKey SeparatorStyleKey
        { 
            get
            {
                return SystemResourceKey.MenuItemSeparatorStyleKey;
            } 
        }
 
        #endregion ItemsStyleKey 
    }
} 


// 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