Click here to Skip to main content
15,867,949 members
Articles / Web Development / HTML

Silverlight 3.0 DropDownMenu

Rate me:
Please Sign up or sign in to vote.
4.35/5 (19 votes)
22 Jul 2009GPL34 min read 127.8K   1.3K   49   61
This is an implementaion of SL 3.0 DropDown Menu like Application MainMenu

Sample Pictures

Main.png

Opened Item

Main-Opened_1_.png

---

Main-Opened_2_.png

CheckBox & RadioButton (Grouping) Support 

Main-Opened_3_.png

Fast Menu Item Access (Underlined char) 

Main-Opened_4_.png

Main-Opened_5_.png

Online Demo Instructions  

Menu activation key gesture is set to "Ctrl" key. When menu activation key is pressed, items that have fast access will be shown with underlined char. If you activate menu with "Ctrl" key, you can open menu items just by pressing an underlined char with "Ctrl" key released.

Introduction    

First of all, I want to apologize for language problems you may experience while reading this article. English is my second language, so sorry for any mis-spellings or language mistakes.

If you take a look to the article's pictures, I think there is no need to explain what it is. The main idea I was driven with is to develop basic application functionality that might be helpful. I think that everybody understands that Silverlight gives us an ability to implement Windows like applications and when it comes to application command navigation, my Menu might be very handy. 

Background

The implementation of this control is a part of a business application that I am working on. The whole thing consists of many additional classes and controls that I will be posting later on. The final package will include:

  1. WindowBase class (modal mode support) - in progress...
  2. ToolStrips - in progress...  
  3. Desktop (Windows like Desktop Emulation) - in progress...
  4. Taskbar  - in progress
  5. DesktopApplication (This is a base class for Desktop's plugin development) - in progress...

Development Tools

The development tools that you need to compile & run this sample are listed below:

  1. Microsoft Visual Studio 2008
  2. Microsoft Expression Blend 3.0 (RCW)
  3. Silverlight SDK 3.0 (RCW)
  4. Microsoft Visual Studio Tools for Silverlight 3.0
  5. Microsoft Silverlight Toolkit July 2009
  6. Silverlight 3.0 RCW Developer Runtime

Key Features

  • Mouse navigation
  • Keyboard navigation
  • Shortcut support
  • Fast menu item access (similar to shortcut)
  • Mixed navigation mode (mouse+keyboard)
  • CheckBox support
  • RadioButton support (MenuItem Grouping)

Note (shortcut support limitations): 

Let me explain a little bit about using the shortcut feature. When the shortcut is being registered within your application, it might not work. This happens because the Browser handles particular shortcuts itself. Little sample. I have registered a shortcut in my sample application as an Action (Close - Ctrl+E). I have never received an event to SL input subsystem because the Browser handled this event that resulted in search bar being activated at the top of browser's window.

The second thing which you have to know about using shortcuts is that the input subsystem limits keyboard navigation in full screen mode.

Code Background  

The code consists of the following classes: 

  1. Menu - Root Menu Implementation 
  2. MenuItem - Menu item implementation
  3. MenuTracker - This object tracks mouse/keyboard events and responsible for Item/SubItem popup functionality/keyboard navigation
  4. MenuKeyGesture  - MenuItem shortcut container
  5. MenuKeyGestureTypeConverter - MenuItem XAML key gesture string converter
  6. ItemAccessKey - Fast menu item access key container
  7. TypeExtensions - Type extension methods

The most functional code is written in MenuItem/MenuTracker classes.

<Menu> Class 

C#
[TemplatePart(Name = "RootElement", Type = typeof(FrameworkElement))]
public class Menu : ItemsControl, IItemsControl
{
    /// <summary>Menu Tracking object instance</summary>
    internal MenuTracker        _menu_tracker;
    /// <summary>Global Menu instance list</summary>
    internal static List<Menu>  _instances;

    /// <summary>Menu Activation Key Gesture ( Default is Key.Ctrl )</summary>
    public static readonly DependencyProperty ActivationKeyGestureProperty = 
	DependencyProperty.Register("ActivationKeyGesture", 
	typeof(MenuKeyGesture), typeof(Menu),
      new PropertyMetadata(new MenuKeyGesture() 
	{ Gesture = Key.Ctrl, ModifierKey = ModifierKeys.None },
        delegate(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
        }));

    /// <summary>Static field initialization</summary>
    static Menu() {
        _instances = new List<Menu>();
    }

    /// <summary>Public class constructor</summary>
    public Menu(){
        //Setting default style key
        base.DefaultStyleKey = typeof(Menu);
        //Hooking loaded event
        Loaded += delegate(object sender, RoutedEventArgs e)
        {
            _menu_tracker = new MenuTracker(this, this, this.GetRoot(), true);
        };
        //We have to add this instance to global instance list for futhure processing
        _instances.Add(this);
    }

    /// <summary>Class Destructor</summary>
    ~Menu()
    {
        //Removing this instance from global instance list
        _instances.Remove(this);
    }

    Guid _uniq_anime_guid = Guid.NewGuid();

    public void AnimatePopup(Popup popup)
    {
        //sample animation - future implementation will possible have templates...
        Storyboard sb = null;
        popup.Child.Opacity = 0;
        if (popup.Resources.Contains(_uniq_anime_guid.ToString()) == false)
        {
            Duration duration = new Duration(TimeSpan.FromMilliseconds(250));
            DoubleAnimation opacity_animation   = 
		new DoubleAnimation() { Duration = duration };
            sb = new Storyboard() { Duration    = duration };
            sb.Children.Add(opacity_animation);
            Storyboard.SetTarget(opacity_animation, popup.Child);
            Storyboard.SetTargetProperty(opacity_animation, 
			new PropertyPath("(UIElement.Opacity)"));
            opacity_animation.To   = 1;
            popup.Resources.Add(_uniq_anime_guid.ToString(), sb);
            sb.Begin();
        }
        else
        {
            sb = popup.Resources[_uniq_anime_guid.ToString()] as Storyboard;
            sb.Begin();
        }
    }

    /// <summary>Closes all opened item's popup windows in all menu instances</summary>
    public static void CloseAllPopups()
    {
        _instances.ForEach(menu =>
            {
                try
                {

                    menu.ClosePopups();
                }
                catch { }
            });
    }

    /// <summary>Returns an item container as MenuItem object</summary>
    /// <returns>New instance of MenuItem object</returns>
    protected override DependencyObject GetContainerForItemOverride()
    {
        return new MenuItem() { };
    }

    /// <summary>Determines if item is MenuItem instance</summary>
    /// <param name="item">item to check</param>
    /// <returns>True - the item is MenuItem, otherwise false</returns>
    protected override bool IsItemItsOwnContainerOverride(object item)
    {
        return item is MenuItem;
    }

    /// <summary>Prepares an item container - container initialization</summary>
    /// <param name="element">Container object</param>
    /// <param name="item">Menu item</param>
    protected override void PrepareContainerForItemOverride
				(DependencyObject element, object item)
    {
        if (element is MenuItem)
        {
            MenuItem container = (element as MenuItem);
            if (IsItemItsOwnContainerOverride(item) == false)
                container.Header    = item;
            container.Menu          = this;
            container.TopLevel      = true;
        }
        base.PrepareContainerForItemOverride(element, item);
    }

    /// <summary>Closes all opened item's popup windows</summary>
    internal void ClosePopups()
    {
        this.Items.OfType<MenuItem>().ToList().ForEach(item =>
            {
                _menu_tracker.CloseAllChildPopups(item, true);
            });
    }

    /// <summary>Gets menu tracker instance</summary>
    internal MenuTracker Tracker
    {
        get { return _menu_tracker; }
    }

    /// <summary>Gets or sets Menu activation key gesture</summary>
    public MenuKeyGesture ActivationKeyGesture
    {
        get { return (MenuKeyGesture)GetValue(ActivationKeyGestureProperty); }
        set { SetValue(ActivationKeyGestureProperty, value); }
    }

    /// <summary>Gets Items collection for internal use</summary>
    IEnumerable<MenuItem> IItemsControl.InternalItems
    {
        get { return Items.OfType<MenuItem>(); }
    }
}

This class contains a property that is not functional "Orientation". :O) for the later implementation...

If you take a look at the code, you will see a static field named "_instances". This one is used in "MenuTracker" object for closing all opened menu items for multi-instantiated Menu classes when you left click anywhere on your page and it is not a MenuItem object.

The control styling is done in the class constructor: 

C#
base.DefaultStyleKey = typeof(Menu);

All styles must be stored in a solution folder named "Themes" in single file "generic.xaml".
Let's take a look at Menu style:

XML
<!--MENU STYLE-->
<Style TargetType="local:Menu">
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="local:Menu">
                <Grid x:Name="RootElement" Visibility="Visible" Background="#9999DDF0" >
                    <Border Background="{TemplateBinding Background}" 
			BorderBrush="{TemplateBinding BorderBrush}" 
			BorderThickness="{TemplateBinding BorderThickness}" 
			Margin="{TemplateBinding Margin}" 
			Padding="{TemplateBinding Padding}">
                        <ItemsPresenter/>
                    </Border>
                </Grid>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
    <Setter Property="ItemsPanel">
        <Setter.Value>
            <ItemsPanelTemplate>
                <toolkit:WrapPanel ItemHeight="25" Margin="2,2,2,2" 
			HorizontalAlignment="Stretch" VerticalAlignment="Center"/>
            </ItemsPanelTemplate>
        </Setter.Value>
    </Setter>
</Style>

The namespace prefix stands for a local project namespace:

XML
xmlns:local="clr-namespace:System.Windows.Controls;assembly=DropDownMenu"

<MenuItem> Class

Let's take a look at MenuItem class: 

C#
[
    TemplatePart(Name = "RootElement",      Type = typeof(FrameworkElement)),
    TemplatePart(Name = "PART_Popup",       Type = typeof(Popup)),
    TemplatePart(Name = "PART_PopupTopRect",Type = typeof(Rectangle)),
    TemplatePart(Name = "PART_Selected",    Type = typeof(FrameworkElement)),
    TemplatePart(Name = "PART_Opened",      Type = typeof(FrameworkElement)),
    TemplatePart(Name = "PART_Header",      Type = typeof(ContentControl)),
    TemplatePart(Name = "PART_LeftBar",     Type = typeof(FrameworkElement)),
    TemplatePart(Name = "PART_HitTest",     Type = typeof(FrameworkElement)),
    TemplatePart(Name = "PART_Separator",   Type = typeof(FrameworkElement)),
    TemplatePart(Name = "PART_SubMenuGrip", Type = typeof(FrameworkElement)),
    ContentProperty("Items")
]
public class MenuItem : Control, IItemsControl
{
    /// <summary>This is a container object for fast menu item access 
    /// (shortcut)</summary>
    public class ItemAccessKey{
        public string Key       { get; set; }
        public Border Border    { get; set; }
    }

    private     System.Windows.Controls.Primitives.Popup _popup;
    private     ContentControl      _HeaderControl;
    private     FrameworkElement    _PART_Seperator, 
				_PART_Selected, _PART_Opened, _RootElement;
    private     Rectangle           _PART_LeftBar, _PART_PopupTopRect, _PART_HitTest;
    private     FrameworkElement    _PART_SubMenuGrip;
    internal    MenuTracker         _menu_tracker;
    private     ItemAccessKey       _accessKey = null;
    private     bool                _is_highlighted;
    private     bool                _is_Opended;

    public static readonly DependencyProperty CommandProperty = 
	DependencyProperty.RegisterAttached("Command", 
	typeof(ICommand), typeof(MenuItem),
    	new PropertyMetadata(null, delegate(DependencyObject d, 
	DependencyPropertyChangedEventArgs e){
    }));
    
    public static readonly DependencyProperty IsCheckedProperty = 
	DependencyProperty.RegisterAttached("IsChecked", typeof(bool), typeof(MenuItem),
    new PropertyMetadata(false, delegate(DependencyObject d, 
				DependencyPropertyChangedEventArgs e)
    {
        MenuItem item = d as MenuItem;
        if ( item != null && string.IsNullOrEmpty(item.GroupName) == 
					false && ((bool)e.NewValue) )
        {
            //group name exists
            IEnumerable<MenuItem> gr_items = null;
            if (item.ParentItem != null)
            {
                gr_items = (from i in item.ParentItem.Items 
                                                  where i.GroupName == item.GroupName 
                                                  select i);
                if ( gr_items.Count() > 0 )
                {
                    gr_items = gr_items.Where(i => i != item && i.IsChecked);
                    gr_items.ToList().ForEach(i => { i.IsChecked = false; });
                }
            }
            else if( item.Menu != null )
            {
                gr_items = (from i in item.Menu.Items.Cast<MenuItem>()
                            where i.GroupName == item.GroupName
                            select i);
                if (gr_items.Count() > 0)
                {
                    gr_items = gr_items.Where(i => i != item && i.IsChecked);
                    gr_items.ToList().ForEach(i => { i.IsChecked = false; });
                }                   
            }
        }
    }));

    public static readonly DependencyProperty GroupNameProperty = 
	DependencyProperty.RegisterAttached("GroupName", 
	typeof(string), typeof(MenuItem),
        	new PropertyMetadata(null, delegate(DependencyObject d, 
	DependencyPropertyChangedEventArgs e)
        {
        }));

    public static readonly DependencyProperty ItemsProperty = 
	DependencyProperty.RegisterAttached("Items", 
	typeof(ObservableCollection<MenuItem>), typeof(MenuItem),
    	new PropertyMetadata(null, delegate(DependencyObject d, 
	DependencyPropertyChangedEventArgs e){

    }));

    public static readonly DependencyProperty TopLevelProperty = 
	DependencyProperty.RegisterAttached("TopLevel", typeof(bool), typeof(MenuItem),
	new PropertyMetadata(delegate(DependencyObject d, 
	DependencyPropertyChangedEventArgs e){
    }));

    public static readonly DependencyProperty HeaderProperty = 
	DependencyProperty.RegisterAttached("Header", typeof(object), typeof(MenuItem),
    new PropertyMetadata(delegate(DependencyObject d, 
		DependencyPropertyChangedEventArgs e){
    }));
    public static readonly DependencyProperty IsMouseOverProperty = 
	DependencyProperty.Register("IsMouseOver", 
			typeof(bool), typeof(MenuItem), null);

    public static readonly DependencyProperty KeyGestureProperty = 
	DependencyProperty.Register("KeyGesture", 
	typeof(MenuKeyGesture), typeof(MenuItem),
      	new PropertyMetadata(new MenuKeyGesture() 
	{ Gesture = Key.None, ModifierKey = ModifierKeys.None },
        	delegate(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            MenuItem item = d as MenuItem;
            if (item != null)
            {
                if (e.NewValue != null)
                {
                    MenuKeyGesture gestute = e.NewValue as MenuKeyGesture;
                    if (gestute.Gesture != Key.None)
                    {
                        System.Windows.Automation.AutomationProperties.
				SetAcceleratorKey(item, gestute.ToString());
                    }
                }
            }
        }));

    public event RoutedEventHandler Click;
    public event RoutedEventHandler Opening;
    public event RoutedEventHandler Opened;

    public MenuItem()
    {
        TopLevel = false;
        SetValue(ItemsProperty, new ObservableCollection<MenuItem>());
        Items.CollectionChanged += 
	new System.Collections.Specialized.NotifyCollectionChangedEventHandler
	(OnItems_CollectionChanged);
        base.DefaultStyleKey = typeof(MenuItem);
    }

    protected void OnItems_CollectionChanged(object sender, 
	System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
    {
        switch (e.Action)
        {
            case System.Collections.Specialized.NotifyCollectionChangedAction.Add:
                if (e.NewItems != null)
                    e.NewItems.Cast<MenuItem>().ToList().ForEach(item =>
                        {
                            if (TopLevel == false && Items.Count > 0 && 
				_PART_SubMenuGrip != null)
                                _PART_SubMenuGrip.Visibility = Visibility.Visible;
                            item.TopLevel = false;
                            item.Menu       = this.Menu;
                            item.ParentItem = this;
                        });
                break;
        }
    }

    protected void InitializeChildren(MenuItem item)
    {
        item.Items.ToList().ForEach(i =>
            {
                i.Menu = Menu;
                i.ParentItem = item;
                InitializeChildren(i);
            });
    }
    
    public override void OnApplyTemplate()
    {
        base.OnApplyTemplate();
        
        _RootElement        = (FrameworkElement)GetTemplateChild("RootElement");
        _popup              = (Popup)GetTemplateChild("PART_Popup");
        _PART_PopupTopRect  = (Rectangle)GetTemplateChild("PART_PopupTopRect");
        _popup.IsOpen       = false;
        _PART_Selected      = (FrameworkElement)GetTemplateChild("PART_Selected");
        _PART_Opened        = (FrameworkElement)GetTemplateChild("PART_Opened");
        _HeaderControl      = (ContentControl)GetTemplateChild("PART_Header");
        _PART_LeftBar       = (Rectangle)GetTemplateChild("PART_LeftBar");
        _PART_HitTest       = (Rectangle)GetTemplateChild("PART_HitTest");
        _PART_Seperator     = (FrameworkElement)GetTemplateChild("PART_Separator");
        _PART_SubMenuGrip   = (FrameworkElement)GetTemplateChild("PART_SubMenuGrip");
        _menu_tracker       = new MenuTracker(Menu, this, 
				_popup.Child as FrameworkElement, false);

        InitializeChildren(this);

        if (TopLevel == false)
        {
            if ( Items.Count > 0 && _PART_SubMenuGrip != null )
                _PART_SubMenuGrip.Visibility = Visibility.Visible;
            if (_RootElement != null)
            {
                bool IsSeparator = Header != null && Header.ToString().Equals("-");
                _RootElement.Height = Header != null && 
			Header.ToString().Equals("-") ? 7 : 26;
                if (IsSeparator)
                    _PART_Seperator.Visibility = Visibility.Visible;
                else
                    _PART_Seperator.Visibility = Visibility.Collapsed;
            }
            if (_HeaderControl != null)
            {
                _HeaderControl.HorizontalAlignment = HorizontalAlignment.Left;
                _HeaderControl.Margin = new Thickness(4, 0, 0, 0);
            }
            if (_PART_LeftBar != null)
                _PART_LeftBar.Visibility = Visibility.Visible;
            if (_PART_Opened != null && _PART_Opened is Border)
                (_PART_Opened as Border).CornerRadius = new CornerRadius(2, 0, 2, 2);
        }
        else
        {
            if (_RootElement is Grid)
                (_RootElement as Grid).ColumnDefinitions[2].Width = new GridLength(6d);
            _PART_Seperator.Visibility = Visibility.Collapsed;
            if (_PART_Opened != null && _PART_Opened is Border)
                (_PART_Opened as Border).CornerRadius = new CornerRadius(2, 2, 0, 2);
            if (_HeaderControl != null)
                _HeaderControl.Margin = new Thickness(-17, 0, 0, 0);
        }

        if (IsHighlighted)
        {
            if (_PART_Selected != null)
                _PART_Selected.Visibility = Visibility.Visible;
        }

        bool    IsHeaderTextFound   = false;
        string  HeaderText          = string.Empty;

        if (Header != null && typeof(string) == 
	Header.GetType() && Header.ToString().Length >= 2 &&
          Header.ToString().Contains('_'))
        {
            IsHeaderTextFound = true;
            HeaderText = Header.ToString();
        }
        else if ( Header != null && Header is FrameworkElement )
        {
            HeaderText = FindAccessKeyHeaderControlText(Header as FrameworkElement);
            if (string.IsNullOrEmpty(HeaderText) == false 
		&& HeaderText.Length >= 2 && HeaderText.Contains('_'))
                IsHeaderTextFound = true;
            else
                HeaderText = null;
        }

        if( IsHeaderTextFound )
        {
            char[] h_text = HeaderText.ToCharArray();
            Grid h_panel = new Grid() { };

            if (Header is string)
                Header = h_panel;
            else
            {
                //this is a point of interest, because we have 
	       //to replace text control with our template...
                FrameworkElement h_control = 
		FindAccessKeyHeaderControl(Header as FrameworkElement);
                if (h_control is ContentControl)
                    (h_control as ContentControl).Content = h_panel;
                else
                    return;
            }

            double x = 0;
            TextBlock t = new TextBlock()
            {
                Text = "",
                FontFamily = FontFamily,
                FontSize = FontSize,
                FontWeight = FontWeight,
                FontStyle = FontStyle,
                FontStretch = FontStretch,
                Foreground = Foreground,
                Margin = new Thickness(0, 0, 0, 0),
                VerticalAlignment = VerticalAlignment.Top,
                HorizontalAlignment = HorizontalAlignment.Left
            };

            h_panel.Children.Add(t);
            double last_width = 0;
            for (int i = 0; i < h_text.Length; i++)
            {
                last_width = t != null ? t.ActualWidth : 0;

                if (h_text[i].ToString().Equals("_") == false)
                {
                    Run run = new Run()
                    {
                        Text = h_text[i].ToString(),
                        FontFamily = FontFamily,
                        FontSize = FontSize,
                        FontWeight = FontWeight,
                        FontStyle = FontStyle,
                        FontStretch = FontStretch,
                        Foreground = Foreground,
                    };
                    t.Inlines.Add(run);
                }
                if (_accessKey == null && h_text[i].ToString().Equals("_"))// Access Key
                {
                    Run run = new Run()
                    {
                        Text = h_text[i + 1].ToString(),
                        FontFamily = FontFamily,
                        FontSize = FontSize,
                        FontWeight = FontWeight,
                        FontStyle = FontStyle,
                        FontStretch = FontStretch,
                        Foreground = Foreground,
                    };
                    t.Inlines.Add(run);
                    if (t != null)
                        t.UpdateLayout();
                    this.UpdateLayout();
                    _accessKey = new ItemAccessKey()
                    {
                        Border = new Border()
                        {
                            BorderThickness = new Thickness(0, 0, 0, 1),
                            BorderBrush = Foreground,
                            Margin = new Thickness(x, t != null ? 
					t.ActualHeight - 4 : 0, 0, 0),
                            VerticalAlignment = VerticalAlignment.Top,
                            HorizontalAlignment = HorizontalAlignment.Left,
                            Width = t.ActualWidth - last_width,
                            Height = 2
                        },
                        Key = i + 1 < h_text.Length ? h_text[i + 1].ToString() : ""
                    };
                    h_panel.Children.Add(_accessKey.Border);
                    i++;
                }
                if (t != null)
                    t.UpdateLayout();
                this.UpdateLayout();
                x += t != null ? (t.ActualWidth + 0.1) - last_width : 0;
            }
            if (_accessKey != null)
                _accessKey.Border.Opacity = 0.0d;
        }
        else if (Header != null && typeof(string) == Header.GetType() 
	&& /*This is a separator string*/ Header.ToString().Equals("-") == false )
        {
            TextBlock t = null;
            t = new TextBlock()
            {
                Text = Header.ToString(),
                FontFamily = FontFamily,
                FontSize = FontSize,
                FontWeight = FontWeight,
                FontStyle = FontStyle,
                FontStretch = FontStretch,
                Foreground = Foreground,
                Margin = new Thickness(0, 0, 0, 0),
                VerticalAlignment = VerticalAlignment.Top,
                HorizontalAlignment = HorizontalAlignment.Left
            };
            Header = t;
        }
    }

    /// <summary>This method searches an element in Header control tree 
    /// for ContentControl/TextBlock control</summary>
    /// <param name="element">Header root element</param>
    /// <returns>control text if exist</returns>
    public string FindHeaderControlText(FrameworkElement element)
    {
        int count = VisualTreeHelper.GetChildrenCount(element);
        string ret_data = null;
        if (count > 0)
        {
            for (int i = 0; i < count; i++)
            {
                DependencyObject child = VisualTreeHelper.GetChild(element, i);
                if (child is FrameworkElement)
                {
                    if (child is ContentControl || child is TextBlock)
                    {
                        if (child is TextBlock)
                        {
                            ret_data = (child as TextBlock).Text;
                            return ret_data;
                        }
                        else if (child is ContentControl)
                        {
                            if ((child as ContentControl).Content != null && 
				((child as ContentControl).Content is string))
                                ret_data = (child as ContentControl).Content.ToString();
                            else if ((child as ContentControl).Content 
						is FrameworkElement)
                            {
                                ret_data = FindHeaderControlText((child 
				as ContentControl).Content as FrameworkElement);
                            }
                        }
                        if( string.IsNullOrEmpty(ret_data) == false )
                            return ret_data;
                    }
                }
                if (ret_data != null)
                    return ret_data;
                if (child != null && child.GetType() == typeof(FrameworkElement))
                    FindHeaderControlText(child as FrameworkElement);
            }
        }
        else
        {
            if (element is TextBlock)
            {
                ret_data = (element as TextBlock).Text;
                return ret_data;
            }
            else if (element is ContentControl)
            {
                if ((element as ContentControl).Content != null && 
			((element as ContentControl).Content is string))
                    ret_data = (element as ContentControl).Content.ToString();
                else if ((element as ContentControl).Content is FrameworkElement)
                {
                    ret_data = FindHeaderControlText((element 
			as ContentControl).Content as FrameworkElement);
                }
            }
            return ret_data;
        }
        return ret_data;
    }

    /// <summary>This method searches Header Control with Tag set to 'AccessKey'
    /// </summary>
    /// <param name="element">Header root element</param>
    /// <returns>control text if exist</returns>
    public string FindAccessKeyHeaderControlText(FrameworkElement element)
    {
        int count = VisualTreeHelper.GetChildrenCount(element);
        string ret_data = null;
        if (count > 0)
        {
            for (int i = 0; i < count; i++)
            {
                DependencyObject child = VisualTreeHelper.GetChild(element, i);
                if (child is FrameworkElement && 
		(child as FrameworkElement).Tag != null &&
                  	(child as FrameworkElement).Tag.GetType() == typeof(string) &&
                  	string.IsNullOrEmpty((child as FrameworkElement).Tag.ToString()) 
								== false &&
	         (child as FrameworkElement).Tag.ToString().ToLower().
							Equals("accesskey"))
                {
                    if (child is ContentControl || child is TextBlock )
                    {
                        if( child is TextBlock )
                        {
                            ret_data = (child as TextBlock).Text;
                            return ret_data;
                        }
                        else if (child is ContentControl)
                        {
                            if ((child as ContentControl).Content != null && 
				((child as ContentControl).Content is string))
                                ret_data = (child as ContentControl).Content.ToString();
                            else if( (child as ContentControl).Content 
						is FrameworkElement )
                            {
                                ret_data = FindAccessKeyHeaderControlText
			     ((child as ContentControl).Content as FrameworkElement);
                            }
                        }
                        return ret_data;
                    }
                }
                if ( ret_data != null )
                    return ret_data;
                if( child != null && child.GetType() == typeof(FrameworkElement) )
                    FindAccessKeyHeaderControlText(child as FrameworkElement);
            }
        }
        return ret_data;
    }

    /// <summary>This method searches Header control that contains string</summary>
    /// <param name="element">Header root element</param>
    /// <returns>Control if exist</returns>
    public FrameworkElement FindAccessKeyHeaderControl(FrameworkElement element)
    {
        int count = VisualTreeHelper.GetChildrenCount(element);
        FrameworkElement ret_data = null;
        if (count > 0)
        {
            for (int i = 0; i < count; i++)
            {
                DependencyObject child = VisualTreeHelper.GetChild(element, i);
                if (child is FrameworkElement && (child as FrameworkElement).Tag 
								!= null &&
                    (child as FrameworkElement).Tag.GetType() == typeof(string) &&
                    string.IsNullOrEmpty((child 
			as FrameworkElement).Tag.ToString()) == false &&
                    (child as FrameworkElement).Tag.ToString().ToLower().
						Equals("accesskey"))
                {
                    if (child is ContentControl)
                    {
                        ret_data = child as FrameworkElement;
                        return ret_data;
                    }
                }
                if (ret_data != null)
                    return ret_data;
                if (child != null && child.GetType() == typeof(FrameworkElement))
                    FindAccessKeyHeaderControlText(child as FrameworkElement);
            }
        }
        return ret_data;
    }

    /// <summary>Activates MenuItem key stroke ( Underlined access symbol )</summary>
    /// <param name="IsActive">Show/Hide underline rectangle</param>
    internal void ActivateAccessKey( bool IsActive )
    {
        if (_accessKey != null)
            _accessKey.Border.Opacity = IsActive ? 1.0d : 0.0d;
    }

    /// <summary>This method handles mouse enter event and 
    /// sets IsMouseOver property to True</summary>
    /// <param name="e">Mouse event args</param>
    protected override void OnMouseEnter(MouseEventArgs e)
    {
        base.OnMouseEnter(e);
        if (IsEnabled)
            IsMouseOver = true;
    }

    /// <summary>This method handles mouse leave event and sets 
    /// IsMouseOver property to False</summary>
    /// <param name="e">Mouse event args</param>
    protected override void OnMouseLeave(MouseEventArgs e)
    {
        base.OnMouseLeave(e);
        IsMouseOver = false;
        if (IsOpened == false)
        {
            if (TopLevel)
            {
                MenuTracker tracker = Menu.Tracker;
                if (tracker.IsMenuActivated)
                {
                    IsHighlighted = true;
                    return;
                }
            }
            IsHighlighted = false;
        }
    }

    /// <summary>Adds MenuItem</summary>
    /// <param name="item"></param>
    public void Add(MenuItem item)
    {
        Items.Add(item);
    }

    /// <summary>Fires up click event</summary>
    internal void FireClickEvent()
    {
        OnClick(new RoutedEventArgs());
    }

    /// <summary></summary>
    /// <param name="e"></param>
    protected virtual void OnClick(RoutedEventArgs e)
    {
        //check group name - existence is radio like button behaviour
        if( string.IsNullOrEmpty(GroupName) == true )
            IsChecked = !IsChecked;
        else if( IsChecked == false )
            IsChecked = !IsChecked;
        if (Click != null)
            Click(this, e);
    }

    /// <summary>Gets or sets checked state</summary>
    public bool IsChecked
    {
        get { return (bool)GetValue(IsCheckedProperty); }
        set { SetValue(IsCheckedProperty, value); }
    }

    /// <summary>Gets ot sets checked state group</summary>
    public string GroupName
    {
        get { return (string)GetValue(GroupNameProperty); }
        set { SetValue(GroupNameProperty, value); }
    }

    IEnumerable<MenuItem> IItemsControl.InternalItems
    {
        get { return Items; }
    }

    internal ItemAccessKey AccessKey
    {
        get { return _accessKey; }
    }

    internal MenuTracker Tracker
    {
        get { return _menu_tracker; }
    }

    public ObservableCollection<MenuItem> Items
    {
        get { return (ObservableCollection<MenuItem>)GetValue(ItemsProperty); }
    }

    public bool IsMouseOver
    {
        get
        {
            return (bool)this.GetValue(IsMouseOverProperty);
        }
        internal set
        {
            base.SetValue(IsMouseOverProperty, value);
        }
    }

    public object Header
    {
        get { return GetValue(HeaderProperty); }
        set { SetValue(HeaderProperty, value); }
    }

    public MenuKeyGesture KeyGesture
    {
        get { return (MenuKeyGesture)GetValue(KeyGestureProperty); }
        set { SetValue(KeyGestureProperty, value); }
    }

    public ICommand Command
    {
        get { return (ICommand)GetValue(CommandProperty); }
        set { SetValue(CommandProperty, value); }
    }

    public bool TopLevel
    {
        get { return (bool)GetValue(TopLevelProperty); }
        set { SetValue(TopLevelProperty, value); }
    }

    public bool IsOpened
    {
        get { return _is_Opended; }
        set { _is_Opended = value; }
    }

    internal void SetHighlightedDirect(bool value)
    {
        _is_highlighted = value;
        if (value)
        {
            if (_PART_Selected != null)
                _PART_Selected.Visibility = Visibility.Visible;
        }
        else
        {
            if (_PART_Selected != null)
                _PART_Selected.Visibility = Visibility.Collapsed;
        }
    }

    public bool IsHighlighted
    {
        get
        {
            return _is_highlighted;
        }
        set
        {
            if ((Header != null && Header.ToString().Equals("-")) || IsEnabled == false)
                return;
            _is_highlighted = value;
            if (value)
            {
                if (IsOpened && TopLevel)
                    return;
                if (_PART_Selected != null)
                    _PART_Selected.Visibility = Visibility.Visible;
            }
            else
            {
                if (IsOpened)
                    return;
                if (_PART_Selected != null)
                    _PART_Selected.Visibility = Visibility.Collapsed;
            }
        }
    }

    public void HidePopup()
    {
        if (IsOpened == false)
            return;
        IsOpened = false;
        _popup.IsOpen = false;
        IsHighlighted = false;
        if (TopLevel)
        {
            if (_PART_Selected != null)
                _PART_Selected.Visibility = Visibility.Collapsed;
            if (_PART_Opened != null)
                _PART_Opened.Visibility = Visibility.Collapsed;
        }
    }

    public void ShowPopup(Point position)
    {
        if ( IsOpened )
            return;
        IsOpened        = true;
        IsHighlighted   = true;

        if (TopLevel == true)
        {
            if (_PART_Selected != null)
                _PART_Selected.Visibility = Visibility.Collapsed;
            if (_PART_Opened != null)
                _PART_Opened.Visibility = Visibility.Visible;
        }

        Items.OfType<MenuItem>().Where(i => i._PART_Selected 
				!= null).ToList().ForEach( item =>
            {
                item._PART_Selected.Visibility = Visibility.Collapsed;
            });

        if (TopLevel)
        {
            _PART_PopupTopRect.Visibility = Visibility.Visible;
            _PART_PopupTopRect.Width = ActualWidth - 2;
        }

        _popup.HorizontalOffset = position.X;
        _popup.VerticalOffset   = position.Y;

        Application.Current.RootVisual.MouseLeftButtonDown += 
		new MouseButtonEventHandler(OnRootVisual_MouseLeftButtonDown);
        _popup.Closed += delegate(object popup_closed, EventArgs popup_args)
        {
            Application.Current.RootVisual.MouseLeftButtonDown -= 
		new MouseButtonEventHandler(OnRootVisual_MouseLeftButtonDown);
        };

        OnPopupOpening(new RoutedEventArgs());
        //lets make some animation.....
        _popup.IsOpen = true;
        Menu.AnimatePopup(_popup);
        OnPopupOpened(new RoutedEventArgs());
    }

    protected void OnPopupOpening(RoutedEventArgs e) {
        if (Opening != null)
            Opening(this, e);
    }
    
    protected void OnPopupOpened(RoutedEventArgs e) {
        if (Opened != null)
            Opened(this, e);
    }

    protected void OnRootVisual_MouseLeftButtonDown
			(object sender, MouseButtonEventArgs e)
    {
        this._menu_tracker.CloseAllChildPopups(this, true);
    }

    public MenuItem ParentItem
    {
        get;
        set;
    }

    public Menu Menu
    {
        get;
        set;
    }

    public FrameworkElement RootElement
    {
        get { return _RootElement; }
    }

    public Rectangle HitTestArea
    {
        get { return _PART_HitTest; }
    }

    public System.Windows.Controls.Primitives.Popup Popup
    {
        get { return _popup; }
    }
    public bool HasKeyGesture
    {
        get { return KeyGesture != null && KeyGesture.Gesture != Key.None; }
    }

    public bool HasOpenedChild
    {
        get
        {
            return (from child in Items.Cast<MenuItem>() 
		where child.IsOpened select child).Count() > 0;
        }
    }

    public MenuItem OpenedChild 
    {
        get
        {
            return (from child in Items.Cast<MenuItem>() 
		where child.IsOpened select child).First();
        }
    }

    public MenuItem GetLastOpenedChild()
    {
        MenuItem ret_val = null;
        if (HasOpenedChild)
            GetLastOpenedChild(OpenedChild, ref ret_val);
        return ret_val;
    }

    public MenuItem GetHighlightedChild()
    {
        IEnumerable<MenuItem> found = 
	(from item in Items.Cast<MenuItem>() where item.IsHighlighted select item);
        if (found.Count() > 0)
            return found.First();
        return null;
    }

    protected void GetLastOpenedChild(MenuItem item, ref MenuItem LastOpened)
    {
        if (item.IsOpened)
            LastOpened = item;
        if (item.HasOpenedChild)
            item.GetLastOpenedChild(item.OpenedChild, ref LastOpened);
    }

    public bool IsSeparator
    {
        get { return Header != null && Header.ToString().Equals("-"); }
    }
}

The styling method for this class is the same as for Menu class and is done in the class constructor:

C#
public MenuItem()
{
    TopLevel = false;
    SetValue(ItemsProperty, new ObservableCollection<MenuItem>());
    Items.CollectionChanged += 
	new System.Collections.Specialized.NotifyCollectionChangedEventHandler
	(OnItems_CollectionChanged);
    base.DefaultStyleKey = typeof(MenuItem);
}

The style for MenuItem:

XML
<local:MenuKeyGestureValueConverter x:Key="GestureConverter"/>
<local:BooleanToVisibilityConverter x:Key="BooleanVisibilityConveter"/>

<!--MENU ITEM STYLE-->
<Style TargetType="local:MenuItem">
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="local:MenuItem">
                <Grid Opacity="1.0" x:Name="RootElement" 
		Visibility="Visible" Height="Auto" Width="Auto" >
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition MinWidth="19" Width="26"/>
                        <ColumnDefinition Width="*"/>
                        <ColumnDefinition Width="26"/>
                    </Grid.ColumnDefinitions>
                    <Rectangle Margin="2,0,0,0" Grid.Column="0" 
			Visibility="Collapsed" x:Name="PART_LeftBar">
                        <Rectangle.Fill>
                            <LinearGradientBrush  EndPoint="0.5,1" StartPoint="0.5,0">
                                <GradientStop Color="#FFE9E8E8" Offset="0"/>
                                <GradientStop Color="#FFE9E8E8" Offset="1"/>
                            </LinearGradientBrush>
                        </Rectangle.Fill>
                    </Rectangle>
                    <Border Grid.ColumnSpan="4" Visibility="Collapsed" 
			Background="#FFF5F5F5" BorderBrush="#FF868686" 
			x:Name="PART_Opened" BorderThickness="1" 
			CornerRadius="2,2,2,0"/>
                    <Grid  x:Name="PART_Selected" Margin="0,0,0,0" 
			Grid.ColumnSpan="4" Visibility="Collapsed">
                        <Grid.RowDefinitions>
                            <RowDefinition Height="0.5*"/>
                            <RowDefinition Height="0.5*"/>
                        </Grid.RowDefinitions>
                        <Rectangle Stroke="#FF9FBBE3" StrokeThickness="0.05" 
			RadiusX="2" RadiusY="2" Grid.RowSpan="2" x:Name="rectangle1">
                            <Rectangle.Fill>
                                <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
                                    <GradientStop Color="#FFDAE4EF" Offset="0"/>
                                    <GradientStop Color="#FFECEBC0" Offset="1"/>
                                </LinearGradientBrush>
                            </Rectangle.Fill>
                        </Rectangle>
                        <Rectangle Grid.RowSpan="2" Margin="2,2,2,2" 
				RadiusX="2" RadiusY="2" x:Name="rectangle2">
                            <Rectangle.Fill>
                                <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
                                    <GradientStop Color="#FFFFFFF9" Offset="0"/>
                                    <GradientStop Color="#FFFFF7B9" Offset="1"/>
                                </LinearGradientBrush>
                            </Rectangle.Fill>
                        </Rectangle>
                        <Rectangle Margin="3,3,3,0" x:Name="rectangle3">
                            <Rectangle.Fill>
                                <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
                                    <GradientStop Color="#FFFFF9D9" Offset="0"/>
                                    <GradientStop Color="#FFFFEEB2" Offset="1"/>
                                </LinearGradientBrush>
                            </Rectangle.Fill>
                        </Rectangle>
                        <Rectangle Margin="3,0,3,3" Grid.Row="1" x:Name="rectangle4">
                            <Rectangle.Fill>
                                <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
                                    <GradientStop Color="#FFFFD66B" Offset="0"/>
                                    <GradientStop Color="#FFFFE086" Offset="1"/>
                                </LinearGradientBrush>
                            </Rectangle.Fill>
                        </Rectangle>
                    </Grid>
                    <Border Grid.ColumnSpan="4" Visibility="Visible" 
			Background="#FF808080" BorderBrush="#FF868686" 
			x:Name="PART_Separator" BorderThickness="1" 
			CornerRadius="0,0,0,0" Width="Auto" Height="1" 
			Margin="30,0,3,0"/>
                    <Grid Grid.Column="1" Width="Auto" Height="Auto">
                        <Grid.ColumnDefinitions>
                            <ColumnDefinition Width="0.5*"/>
                            <ColumnDefinition Width="0.5*"/>
                        </Grid.ColumnDefinitions>
                        <ContentControl Grid.Column="0" 
			VerticalAlignment="Center" HorizontalAlignment="Center" 
			x:Name="PART_Header" Content="{TemplateBinding Header}"/>
                        <TextBlock Grid.Column="1" Margin="10,0,-12,0" 
			VerticalAlignment="Center" HorizontalAlignment="Right"
                            Visibility="{Binding 
                              Path=HasKeyGesture, 
                              RelativeSource={RelativeSource TemplatedParent}, 
                              Converter={StaticResource BooleanVisibilityConveter}}"
                            Text="{Binding 
                              Path=KeyGesture, 
                              RelativeSource={RelativeSource TemplatedParent}, 
                              Converter={StaticResource GestureConverter}}" 
				x:Name="PART_GestureString" TextWrapping="NoWrap">
                            </TextBlock>
                    </Grid>
                    <ContentControl HorizontalAlignment="Center" 
			Grid.Column="3" RenderTransformOrigin="0.5,0" 
			Margin="6,9,2,0" VerticalAlignment="Center" 
			Width="9" Height="9" x:Name="PART_SubMenuGrip" 
			Visibility="Collapsed">
                        <ContentControl.RenderTransform>
                            <TransformGroup>
                                <ScaleTransform/>
                                <SkewTransform/>
                                <RotateTransform Angle="45"/>
                                <TranslateTransform/>
                            </TransformGroup>
                        </ContentControl.RenderTransform>
                        <ContentControl.Content>
                            <Canvas Width="9" Height="9" 
				HorizontalAlignment="Center" 
				VerticalAlignment="Center">
                                <Polygon Points="0,0 6,0 5,5 0,0"
                                         Stroke="{x:Null}" StrokeThickness="2" 
					x:Name="polygon">
                                    <Polygon.Fill>
                                        <RadialGradientBrush>
                                            <GradientStop Color="#FF000000"/>
                                            <GradientStop Color="#FF000000" Offset="1"/>
                                        </RadialGradientBrush>
                                    </Polygon.Fill>
                                </Polygon>
                            </Canvas>
                        </ContentControl.Content>
                    </ContentControl>
                    <Rectangle Grid.ColumnSpan="3" Fill="White" 
				Opacity="0.01" x:Name="PART_HitTest"/>
                    <Popup x:Name="PART_Popup">
                        <Grid>
                            <Border BorderThickness="1,1,1,1" 
				Background="#FFF5F5F5" BorderBrush="#FF868686" 
				CornerRadius="0,2,2,2"/>
                            <ItemsControl ItemsSource="{TemplateBinding Items}">
                                <ItemsControl.ItemsPanel>
                                    <ItemsPanelTemplate>
                                        <StackPanel x:Name="PART_PopupItemsHost" 
					Orientation="Vertical" Margin="2,2,2,2"/>
                                    </ItemsPanelTemplate>
                                </ItemsControl.ItemsPanel>
                            </ItemsControl>
                            <Rectangle Height="2" Width="80" 
				VerticalAlignment="Top" HorizontalAlignment="Left" 
				Margin="1,-1,0,0" Fill="#FFF5F5F5" 
				x:Name="PART_PopupTopRect" Visibility="Collapsed"/>
                        </Grid>
                    </Popup>
                </Grid>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
    <Setter Property="Foreground" Value="Black"/>
</Style>

Both of the mentioned classes have an instance of MenuTracker object to control MenuItems popup behaviour and keyboard navigation.

<MenuTracker Class>

C#
internal class MenuTracker
    {
        private FrameworkElement _root;
        private bool _tracking;
        private MenuItem _highlighted = null;
        private Menu _menu;
        private IItemsControl _owner;
        private bool _IsRoot = false;
        private bool _menu_was_activated = false;
        private bool _menu_keyboard_navigation = false;
        private bool _last_keyup_was_gesture;
        private bool _do_not_process_next_keyup = false;

        public MenuTracker(Menu menu, IItemsControl owner, 
				FrameworkElement root, bool IsRoot)
        {
            _IsRoot = IsRoot;
            _root = root;
            _owner = owner;
            _menu = menu;
            HookMenu();
        }

        private void HookMenu()
        {
            if (_root != null)
            {
                _root.MouseEnter += new MouseEventHandler(OnMenu_MouseEnter);
                _root.MouseLeave += new MouseEventHandler(OnMenu_MouseLeave);
                _root.MouseMove += new MouseEventHandler(OnMenu_MouseMove);
                _root.MouseLeftButtonDown += 
			new MouseButtonEventHandler(OnMenu_MouseLeftButtonDown);
                
                if (_IsRoot)
                {
                    _root.KeyUp += new KeyEventHandler(OnRoot_KeyUp);
                    _root.KeyDown += new KeyEventHandler(OnRoot_KeyDown);
                }
            }
        }

        protected void OnRoot_KeyDown(object sender, KeyEventArgs e)
        {
            if (_last_keyup_was_gesture)
            {
                _last_keyup_was_gesture = false;
                return;
            }

            if (_IsRoot == true && _menu.ActivationKeyGesture.Gesture == e.Key)
            {
                this._menu_keyboard_navigation = true;
                _menu.Items.Cast<MenuItem>().ToList().ForEach(item =>
                  {
                      ActivateAccessKey(item, true);
                  });
            }
        }

        protected void OnRoot_KeyUp(object sender, KeyEventArgs e)
        {
            MenuItem g_item = null;
            ModifierKeys mod = Keyboard.Modifiers;
            _owner.InternalItems.ToList().ForEach(item =>
              {
                  if (g_item != null)
                      return;
                  g_item = FindItemForGesture(item, e.Key, mod);
              });
            if (g_item != null)
            {
                _last_keyup_was_gesture = true;
                g_item.FireClickEvent();
                _menu.ClosePopups();
                this._menu.Items.Cast<MenuItem>().ToList().ForEach(i =>
                {
                    ActivateAccessKey(i, false);
                });
                _highlighted = null;
                return;
            }
            else
            {
                if ( mod != ModifierKeys.None && _menu_keyboard_navigation == false )
                {
                    _last_keyup_was_gesture = true;
                    return;
                }
                else if (_IsRoot == true && IsMenuActivated == 
		false && _menu_keyboard_navigation && LookUpAccessKeyItem
		(_menu.Items.Cast<MenuItem>(), false, e.PlatformKeyCode))
                {
                    //this is then menu is activated = false;
                    _do_not_process_next_keyup = true;
                    _tracking = true;
                    if (_highlighted != null)
                    {
                        if (_highlighted.IsOpened)
                        {
                            this.CloseAllChildPopups(_highlighted, true);
                            if (_highlighted.IsMouseOver == false)
                            {
                                _highlighted.IsHighlighted = false;
                                _highlighted = null;
                            }
                            else
                                _highlighted.SetHighlightedDirect(true);
                            _menu_keyboard_navigation = false;
                            _menu_was_activated = false;
                            _menu.Items.Cast<MenuItem>().ToList().ForEach(item =>
                            {
                                ActivateAccessKey(item, false);
                            });
                        }
                        else
                        {
                            if (_menu_was_activated)
                            {
                                _highlighted.SetHighlightedDirect(false);
                                _menu_keyboard_navigation = false;
                                _menu_was_activated = false;
                                _menu.Items.Cast<MenuItem>().ToList().ForEach(item =>
                                {
                                    item.ActivateAccessKey(false);
                                });
                            }
                            else
                            {
                                _menu_was_activated = true;
                                this.CloseAllChildPopups(_highlighted, true);
                                _highlighted.IsHighlighted = false;
                                _highlighted = _menu.Items.Count() > 0 
				? _menu.Items.Cast<MenuItem>().First() : null;
                                if (_highlighted != null)
                                {
                                    _highlighted.IsHighlighted = true;
                                }
                            }
                        }
                    }
                    else
                    {
                        _highlighted = _menu.Items.Count() > 0 ? 
			_menu.Items.Cast<MenuItem>().First() : null;
                        if (_highlighted != null)
                        {
                            _highlighted.IsHighlighted = true;
                            _menu_was_activated = true;
                        }
                    }
                }
            }

            //Find an access key for highlighted menu item...
            if (_highlighted != null && ( IsMenuActivated || 
			_menu._menu_tracker.IsMenuActivated ) )
            {
                //this would mean that we have menu activated, 
	       //so we search for an access key for an item in
                //inside of opened menu item.
                if ( _highlighted.IsOpened == false )
                {
                    FindAccessKeyItem(_menu.Items.Cast<MenuItem>(), 
					false, e.PlatformKeyCode);
                }
                else
                {
                    IEnumerable<MenuItem> items = 
			_highlighted.GetLastOpenedChild() != null ?
                        _highlighted.GetLastOpenedChild().Items : _highlighted.Items;
                    FindAccessKeyItem(items, true, e.PlatformKeyCode);
                }
            }
            //***********************************************

            //THIS SECTION IS FOR MENU KEY NAVIGATION....

            if (_last_keyup_was_gesture)
            {
                _last_keyup_was_gesture = false;
                _menu.Items.Cast<MenuItem>().ToList().ForEach(item =>
                {
                    item.ActivateAccessKey(false);
                });
                return;
            }

            if (_IsRoot == true && IsMenuKeyPressed(e.Key))
            {
                if (_do_not_process_next_keyup)
                {
                    _do_not_process_next_keyup = false;
                    return;
                }
                //this is then menu is activated = false;
                _tracking = true;
                if (_highlighted != null)
                {
                    if (_highlighted.IsOpened)
                    {
                        this.CloseAllChildPopups(_highlighted, true);
                        if (_highlighted.IsMouseOver == false)
                        {
                            _highlighted.IsHighlighted = false;
                            _highlighted = null;
                        }
                        else
                            _highlighted.SetHighlightedDirect(true);
                        _menu_keyboard_navigation = false;
                        _menu_was_activated = false;
                        _menu.Items.Cast<MenuItem>().ToList().ForEach(item =>
                        {
                            ActivateAccessKey(item, false);
                        });
                    }
                    else
                    {
                        if (_menu_was_activated)
                        {
                            _highlighted.SetHighlightedDirect(false);
                            _menu_keyboard_navigation = false;
                            _menu_was_activated = false;
                            _menu.Items.Cast<MenuItem>().ToList().ForEach(item =>
                            {
                                item.ActivateAccessKey(false);
                            });
                        }
                        else
                        {
                            _menu_was_activated = true;
                            this.CloseAllChildPopups(_highlighted, true);
                            _highlighted.IsHighlighted = false;
                            _highlighted = _menu.Items.Count() > 0 ? 
				_menu.Items.Cast<MenuItem>().First() : null;
                            if (_highlighted != null)
                            {
                                _highlighted.IsHighlighted = true;
                            }
                        }
                    }
                }
                else
                {
                    _highlighted = _menu.Items.Count() > 0 ? 
			_menu.Items.Cast<MenuItem>().First() : null;
                    if (_highlighted != null)
                    {
                        _highlighted.IsHighlighted = true;
                        _menu_was_activated = true;
                    }
                }
            }

            if (_IsRoot && e.Key == Key.Escape && _menu_was_activated)
            {
                if (_highlighted != null)
                {
                    if (_highlighted.IsOpened)
                    {
                        this.CloseAllChildPopups(_highlighted, true);
                    }
                    if (_highlighted.IsMouseOver == false)
                    {
                        _highlighted.IsHighlighted = false;
                        _highlighted = null;
                    }
                    _menu_keyboard_navigation = false;
                    _menu_was_activated = false;
                    _menu.Items.Cast<MenuItem>().ToList().ForEach(item =>
                    {
                        item.ActivateAccessKey(false);
                    });
                }
            }

            if (_IsRoot && _menu_was_activated || _menu.Tracker.IsMenuActivated)
            {
                NavigateMenu(e.Key);
                if (e.Key == Key.Enter)
                {
                    if (_highlighted != null)
                    {
                        MenuItem last = _highlighted.GetLastOpenedChild();
                        MenuItem active = last != null ? 
		      last.GetHighlightedChild() : _highlighted.GetHighlightedChild();
                        if (active != null)
                        {
                            if (active.Items.Count == 0)
                            {
                                active.FireClickEvent();
                                CloseAllChildPopups(active, true);
                                _menu_keyboard_navigation = false;
                                _menu_was_activated = false;
                                this._menu.Items.Cast<MenuItem>().ToList().ForEach(i =>
                                {
                                    ActivateAccessKey(i, false);
                                });
                                _highlighted = null;
                            }
                            else
                            {
                                ShowPopup(active);
                                active.Items.Cast<MenuItem>().First()
							.IsHighlighted = true;
                            }
                        }
                    }
                }
            }
        }

        protected bool LookUpAccessKeyItem(IEnumerable<MenuItem> items, 
					bool IsRootOpen, int KeyCode)
        {
            IEnumerable<MenuItem> found = (from i in items.Cast<MenuItem>()
                                           where i.AccessKey != null && 
					string.IsNullOrEmpty(i.AccessKey.Key) 
					== false &&
                                           i.AccessKey.Key.Length > 0 &&
                                           i.AccessKey.Key.ToLower() == 
					((char)KeyCode).ToString().ToLower()
                                           select i);
            return found.Count() > 0;
        }

        protected void FindAccessKeyItem(IEnumerable<MenuItem> items, 
					bool IsRootOpen, int KeyCode)
        {
            IEnumerable<MenuItem> found = (from i in items.Cast<MenuItem>()
                                           where i.AccessKey != null && 
					string.IsNullOrEmpty
					(i.AccessKey.Key) == false &&
                                           i.AccessKey.Key.Length > 0 &&
                                           i.AccessKey.Key.ToLower() == 
					((char)KeyCode).ToString().ToLower()
                                           select i);
            if (found.Count() > 0)
            {
                if (found.First().Items.Count == 0)
                {
                    //click
                    _last_keyup_was_gesture = true;
                    found.First().FireClickEvent();
                    _menu.ClosePopups();
                    this._menu.Items.Cast<MenuItem>().ToList().ForEach(i =>
                    {
                        ActivateAccessKey(i, false);
                    });
                    this._menu._menu_tracker._menu_was_activated = false;
                    this._menu._menu_tracker._highlighted = null;
                    _highlighted = null;
                    return;
                }
                else
                {
                    _menu_keyboard_navigation = true;
                    if (found.First().ParentItem != null && 
			found.First().ParentItem.GetHighlightedChild() != null )
                        found.First().ParentItem.GetHighlightedChild().
						IsHighlighted = false;
                    
                    found.First().IsHighlighted = true;

                    //found.First()._menu_tracker._highlighted = found.First();
                    
                    //Navigate to an item we need
                    if (IsRootOpen == false && _highlighted != found.First())
                    {
                        while(_highlighted != found.First())
                            NavigateMenu(Key.Right);
                    }

                    _menu_was_activated = true;
                    //Dropdown item
                    NavigateMenu(IsRootOpen ? Key.Right : Key.Down );
                    //show access key stroke
                    this._menu.Items.Cast<MenuItem>().ToList().ForEach(i =>
                    {
                        ActivateAccessKey(i, true);
                    });
                    return;
                }
            }
        }

        /// <summary>This method implements code for menu keyboard navigation</summary>
        /// <param name="key">The key that was fired by key up event</param>
        protected void NavigateMenu(Key key)
        {
            if (_highlighted != null)
            {
                List<MenuItem> root_items = null;
                MenuItem fh;
                int index = 0;

                switch (key)
                {
                    case Key.Left:
                        if (_highlighted.IsOpened == false)
                        {
                            //find next root item
                            root_items = _menu.Items.Cast<MenuItem>().ToList();
                            index = root_items.IndexOf(_highlighted);
                            if (index == 0)
                                index = root_items.Count - 1;
                            else
                                index = index - 1 >= 0 && index != 0 ? index - 1 : index;
                            _highlighted.IsHighlighted = false;
                            _highlighted = root_items[index];
                            _highlighted.IsHighlighted = true;
                        }
                        else
                        {
                            if (_highlighted.TopLevel)
                            {
                                if (_highlighted.HasOpenedChild)
                                {
                                    MenuItem last = _highlighted.GetLastOpenedChild();
                                    if (last != null)
                                    {
                                        last.HidePopup();
                                        last.IsHighlighted = true;
                                        _menu_keyboard_navigation = true;
                                    }
                                }
                                else//No opened child...
                                {
                                    //find next root item
                                    root_items = _menu.Items.Cast<MenuItem>().ToList();
                                    index = root_items.IndexOf(_highlighted);
                                    if (index == 0)
                                        index = root_items.Count - 1;
                                    else
                                        index = index - 1 >= 0 && 
					index != 0 ? index - 1 : index;
                                    _highlighted.IsHighlighted = false;
                                    CloseAllChildPopups(_highlighted, true);
                                    _highlighted = root_items[index];
                                    _highlighted.IsHighlighted = true;
                                    ShowPopup(_highlighted);
                                    if (_highlighted.Items.Count > 0)
                                    {
                                        _highlighted.Items.Cast
					<MenuItem>().First().IsHighlighted = true;
                                    }
                                }
                            }
                        }
                        break;
                    case Key.Right:
                        if (_highlighted.IsOpened == false)
                        {
                            //find next root item
                            root_items = _menu.Items.Cast<MenuItem>().ToList();
                            index = root_items.IndexOf(_highlighted);
                            if (index == root_items.Count - 1)
                                index = 0;
                            else
                                index = index + 1 
				<= root_items.Count ? index + 1 : index;
                            _highlighted.IsHighlighted = false;
                            _highlighted = root_items[index];
                            _highlighted.IsHighlighted = true;
                        }
                        else
                        {
                            if (_highlighted.TopLevel)
                            {
                                if (_menu_keyboard_navigation == false)
                                {
                                    //find next root item
                                    root_items = _menu.Items.Cast<MenuItem>().ToList();
                                    index = root_items.IndexOf(_highlighted);
                                    if (index == root_items.Count - 1)
                                        index = 0;
                                    else
                                        index = index + 1 
					<= root_items.Count ? index + 1 : index;
                                    _highlighted.IsHighlighted = false;
                                    CloseAllChildPopups(_highlighted, true);
                                    _highlighted = root_items[index];
                                    _highlighted.IsHighlighted = true;
                                    ShowPopup(_highlighted);
                                    if (_highlighted.Items.Count > 0)
                                        _highlighted.Items.Cast
					<MenuItem>().First().IsHighlighted = true;
                                }
                                else if (_menu_keyboard_navigation)
                                {
                                    MenuItem last = _highlighted.GetLastOpenedChild();
                                    MenuItem highlighted = null;
                                    if (last != null)
                                        highlighted = last.GetHighlightedChild();
                                    else
                                        highlighted = _highlighted.GetHighlightedChild();
                                    if (highlighted != null)
                                    {
                                        if (highlighted.Items.Count == 0)
                                        {
                                            //find next root item
                                            root_items = _menu.Items.Cast
							<MenuItem>().ToList();
                                            index = root_items.IndexOf(_highlighted);
                                            if (index == root_items.Count - 1)
                                                index = 0;
                                            else
                                                index = index + 1 
					   <= root_items.Count ? index + 1 : index;
                                            _highlighted.IsHighlighted = false;
                                            CloseAllChildPopups(_highlighted, true);
                                            _highlighted = root_items[index];
                                            _highlighted.IsHighlighted = true;
                                            ShowPopup(_highlighted);
                                            if (_highlighted.Items.Count > 0)
                                                _highlighted.Items.Cast
					<MenuItem>().First().IsHighlighted = true;
                                        }
                                        else
                                        {
                                            ShowPopup(highlighted);
                                            if (highlighted.Items.Count > 0)
                                            {
                                                highlighted = 
					highlighted.Items.Cast<MenuItem>().First();
                                                highlighted.IsHighlighted = true;
                                            }
                                        }
                                    }
                                }
                            }
                        }
                        break;

                    case Key.Up:
                        fh = null;
                        //find next root item
                        if (_highlighted.HasOpenedChild == false)
                            root_items = _highlighted.Items.Cast<MenuItem>().ToList();
                        else
                        {
                            fh = _highlighted.GetLastOpenedChild();
                            root_items = fh.Items.Cast<MenuItem>().ToList();
                        }
                        fh = fh == null ? _highlighted.GetHighlightedChild() : 
						fh.GetHighlightedChild();
                    again_up://this is for a separator to be passed off
                        index = fh != null ? root_items.IndexOf(fh) : 0;
                    if (fh != null)
                    {
                        fh.IsHighlighted = false;
                        CloseAllChildPopups(fh, false);
                    }
                    if (index == 0)
                        index = root_items.Count - 1;
                    else if (fh != null)
                        index = index - 1 >= 0 && index != 0 ? index - 1 : index;
                    fh = root_items[index];
                    if (fh.IsSeparator)
                        goto again_up;
                    fh.IsHighlighted = true;
                    _menu_keyboard_navigation = true;
                    if (_highlighted.IsOpened == false)
                        ShowPopup(_highlighted);
                    break;

                case Key.Down:
                    //find next root item
                    fh = null;
                    if (_highlighted.HasOpenedChild == false)
                        root_items = _highlighted.Items.Cast<MenuItem>().ToList();
                    else
                    {
                        fh = _highlighted.GetLastOpenedChild();
                        root_items = fh.Items.Cast<MenuItem>().ToList();
                    }
                    fh = fh == null ? _highlighted.GetHighlightedChild() : 
						fh.GetHighlightedChild();
                again_down:
                    index = fh != null ? root_items.IndexOf(fh) : 0;
                    if (fh != null)
                    {
                        fh.IsHighlighted = false;
                        CloseAllChildPopups(fh, false);
                    }
                    if (index == root_items.Count - 1)
                        index = 0;
                    else if (fh != null)
                        index = index + 1 <= root_items.Count ? index + 1 : index;
                    fh = root_items[index];
                    if (fh.IsSeparator)
                        goto again_down;
                    if (_highlighted.IsOpened == false)
                        ShowPopup(_highlighted);
                    _menu_keyboard_navigation = true;
                    fh.IsHighlighted = true;
                    _highlighted.IsHighlighted = true;
                    break;
                }
            }
        }

        /// <summary>This method determines if a Menu access key was pressed</summary>
        /// <param name="key">The key that was fired by key up event</param>
        /// <returns>True - the menu key was pressed ( default is Ctrl )</returns>
        protected bool IsMenuKeyPressed(Key key)
        {
            ModifierKeys mod = Keyboard.Modifiers;
            if (_menu.ActivationKeyGesture != null)
            {
                if ((_menu.ActivationKeyGesture.Gesture == key && 
			mod == _menu.ActivationKeyGesture.ModifierKey))
                {
                    return true;
                }
            }
            return false;
        }

        /// <summary>This method searches for menu item with GeyGesture 
        /// that match the passed parameters</summary>
        /// <param name="item">Root Item</param>
        /// <param name="key">The key that was pressed</param>
        /// <param name="mod">The modifier key that was pressed</param>
        /// <returns>MenuItem object if found, otherwise null</returns>
        protected MenuItem FindItemForGesture(MenuItem item, Key key, ModifierKeys mod)
        {
            if (item.KeyGesture != null)
            {
                if (item.KeyGesture.Gesture == key && item.KeyGesture.ModifierKey == mod)
                    return item;
            }
            MenuItem g_item = null;
            item.Items.Cast<MenuItem>().ToList().ForEach(citem =>
              {
                  if (g_item != null)
                      return;
                  g_item = FindItemForGesture(citem, key, mod);
              });
            return g_item;
        }

        /// <summary>This method handles Left Mouse Button down event 
        /// fired by root object of this instance</summary>
        /// <param name="sender">Message sender</param>
        /// <param name="e">Message event args</param>
        protected void OnMenu_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            if (_IsRoot && _highlighted != null)
            {
                FrameworkElement element = _root;
                MenuItem item = _highlighted;
                Point screen_item_location = 
		item.TransformToVisual(element).Transform(new Point(0, 0));
                Point screen_mouse_location = item.TransformToVisual(element).Transform(
                    e.GetPosition(item.HitTestArea));
                Rect bounds = new Rect(screen_item_location.X, 
		screen_item_location.Y, (item as MenuItem).HitTestArea.ActualWidth, 
		(item as MenuItem).HitTestArea.ActualHeight);
                bool is_item_mouse_over = bounds.Contains(screen_mouse_location);
                if (is_item_mouse_over == false)
                {
                    CloseAllChildPopups(_highlighted, true);
                    this._menu.Items.Cast<MenuItem>().ToList().ForEach(i =>
                    {
                        ActivateAccessKey(i, false);
                    });
                    this._menu._menu_tracker._menu_was_activated = false;
                    this._menu._menu_tracker._highlighted = null;
                    _highlighted = null;
                    return;
                }
            }

            if (_highlighted != null)
            {
                if (_highlighted.Items.Count > 0)
                {
                    ShowPopup(_highlighted);
                }
                else if (_highlighted.Items.Count == 0)
                {
                    CloseAllChildPopups(_highlighted, true);
                    _highlighted.FireClickEvent();
                    _tracking = false;
                    _highlighted.IsHighlighted = false;
                    _menu_was_activated = false;
                    //we have to deactivate all parent menu items...
                    if (_highlighted.ParentItem != null)
                    {
                        MenuItem tmp = _highlighted.ParentItem;
                        while (tmp != null)
                        {
                            tmp.IsHighlighted = false;
                            tmp._menu_tracker._menu_was_activated = false;
                            tmp._menu_tracker._highlighted = null;
                            tmp = tmp.ParentItem;
                        }
                    }

                    this._menu.Items.Cast<MenuItem>().ToList().ForEach(i =>
                        {
                            ActivateAccessKey(i, false);
                        });

                    this._menu._menu_tracker._menu_was_activated = false;
                    this._menu._menu_tracker._highlighted = null;
                    _highlighted = null;
                }
            }
        }

        /// <summary>This method enables visual keystroke for menu item if available
        /// </summary>
        /// <param name="item">The item for keystroke to be enabled</param>
        /// <param name="Activate">True-activate(show), False - deactivate(hide)</param>
        protected void ActivateAccessKey(MenuItem item, bool Activate)
        {
            item.ActivateAccessKey(Activate);

            item.Items.Cast<MenuItem>().ToList().ForEach(i =>
            {
                ActivateAccessKey(i, Activate);
            });
        }

        /// <summary>Hides menu item popup</summary>
        /// <param name="item">An item that contains an open popup</param>
        protected void HidePopup(MenuItem item)
        {
            if (item.IsOpened == false)
                return;
            item.HidePopup();
        }

        /// <summary>Shows menu item popup if available</summary>
        /// <param name="item">An item that contains hidden popup</param>
        protected void ShowPopup(MenuItem item)
        {
            if (item.IsOpened || item.Items.Count == 0)
                return;
            
            if (item.TopLevel)
            {
                _menu_was_activated = true;
                FrameworkElement element = _root.GetRoot();
                Point screen_item_location = 
		item.TransformToVisual(element).Transform(new Point(0, 0));
                Rect bounds = new Rect(screen_item_location.X, 
		screen_item_location.Y, item.HitTestArea.ActualWidth, 
		item.HitTestArea.ActualHeight);
                item.ShowPopup(new Point(0, bounds.Height - 3));
                item.Popup.UpdateLayout();
                if ((bounds.Y + bounds.Height - 1 + 
		item.Popup.ActualHeight) > element.Height)
                {
                    item.HidePopup();
                    bounds.Y -= (item.Popup.ActualHeight + bounds.Height);
                    item.ShowPopup(new Point(bounds.X, bounds.Y));
                }
            }
            else
            {
                item.ParentItem.Items.Cast<MenuItem>().ToList().ForEach(ch => 
			{ ch.HidePopup(); });
                FrameworkElement element = _root.GetRoot();
                Point screen_item_location = 
		item.TransformToVisual(element).Transform(new Point(0, 0));
                Rect bounds = new Rect(screen_item_location.X, 
		screen_item_location.Y, item.HitTestArea.ActualWidth, 
		item.HitTestArea.ActualHeight);
                item.ShowPopup(new Point(/*bounds.X + */bounds.Width - 1, 
							1/*bounds.Y*/));
            }
        }

        protected Rect GetPopupBounds(System.Windows.Controls.Primitives.Popup popup)
        {
            Rect bounds = new Rect(0, 0, 
		(popup.Child as FrameworkElement).ActualWidth, 
		(popup.Child as FrameworkElement).ActualHeight);
            return bounds;
        }

        public void CloseAllChildPopups(MenuItem item, bool IncludeParent)
        {
            item.IsHighlighted = false;
            if (IncludeParent && item.ParentItem != null)
            {
                MenuItem tmp = item.ParentItem;
                while (tmp != null)
                {
                    tmp.IsHighlighted = false;
                    tmp.HidePopup();
                    tmp = tmp.ParentItem;
                }
            }
            item.Items.OfType<MenuItem>().ToList().ForEach(nitem =>
                {
                    nitem.IsHighlighted = false;
                    nitem.HidePopup();
                    CloseAllChildPopups(nitem, IncludeParent);
                });
        }

        protected virtual void OnMenu_MouseMove(object sender, MouseEventArgs e)
        {
            if (_tracking)
            {
                List<MenuItem> found = new List<MenuItem>
		(_owner.InternalItems.Where(item => item.IsMouseOver == false));

                found.ForEach(item =>
                {
                    if (_menu_was_activated && item != _highlighted)
                        item.IsHighlighted = false;
                });

                (from item in _owner.InternalItems where item.IsMouseOver == 
			true select item).ToList().ForEach(item =>
                  {
                      if (_highlighted != null && _highlighted != item)
                      {
                          bool _top_level_opened = false;
                          if (item.TopLevel == true)
                          {
                              _top_level_opened = _highlighted.IsOpened;
                              CloseAllChildPopups(_highlighted, false);
                          }
                          HidePopup(_highlighted);
                          _highlighted = item;
                          item.IsHighlighted = true;
                          if (_top_level_opened)
                              ShowPopup(_highlighted);
                          return;
                      }

                      //a keyboard navigated child could be selected & highlighted
                      if (_menu_keyboard_navigation && item.ParentItem 
			!= null && item.ParentItem.GetHighlightedChild() != null)
                      {
                          MenuItem hitem = item.ParentItem.GetHighlightedChild();
                          CloseAllChildPopups(hitem, false);
                          hitem.IsHighlighted = false;
                          hitem.HidePopup();
                      }

                      _highlighted = item;
                      item.IsHighlighted = true;

                      if (item.TopLevel == false)
                      {
                          ShowPopup(_highlighted);
                      }
                  });
                if (_highlighted != null && _menu_was_activated)
                {
                    _highlighted.IsHighlighted = true;
                }
            }
        }

        protected virtual void OnMenu_MouseEnter(object sender, MouseEventArgs e){
            _tracking = true;
        }

        protected virtual void OnMenu_MouseLeave(object sender, MouseEventArgs e) {
        }

        public bool IsMenuActivated
        {
            get { return _menu_was_activated; }
        }
    }

The main trick of this object is that when a Menu class constructor code is executed, it runs the following code to create a MenuTracker class instance:

C#
Loaded += delegate(object sender, RoutedEventArgs e)
{
  _menu_tracker = new MenuTracker(this, this, this.GetRoot(), true);
};

The third parameter for a MenuTracker class constructor is root element that will catch & handle mouse events such as MouseEnter, MouseMove and MouseDown. That is how root menu items are populated & highlighted. The same way is used to control submenu items popup behaviour. Each MenuItem class instance contains an instance of a MenuTracker and the parameter mentioned before is Popup object of a particular MenuItem.

The mouse events handlers are hooked in method "HookMenu()".

C#
private void HookMenu()
{
    if (_root != null)
    {
        _root.MouseEnter += new MouseEventHandler(OnMenu_MouseEnter);
        _root.MouseLeave += new MouseEventHandler(OnMenu_MouseLeave);
        _root.MouseMove += new MouseEventHandler(OnMenu_MouseMove);
        _root.MouseLeftButtonDown += new MouseButtonEventHandler
					(OnMenu_MouseLeftButtonDown);
        
        if (_IsRoot)
        {
            _root.KeyUp += new KeyEventHandler(OnRoot_KeyUp);
            _root.KeyDown += new KeyEventHandler(OnRoot_KeyDown);
        }
    }
}

The Code Usage Sample

XML
<UserControl x:Class="DropDownMenu.Page"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    xmlns:local2="clr-namespace:System.Windows.Controls;assembly=ToolStrips"
    xmlns:local="clr-namespace:System.Windows.Controls;assembly=DropDownMenu"
    xmlns:s="clr-namespace:System;assembly=mscorlib"
    Width="Auto" Height="Auto">
    <Grid Background="Gray">
        <Border  
          Width="600" 
          Height="400" 
          VerticalAlignment="Center" 
          HorizontalAlignment="Center"          
          BorderBrush="#FF084C64" 
          BorderThickness="3,3,3,3" 
          CornerRadius="3,3,3,3" >
            <Grid  x:Name="LayoutRoot" Background="#FF75CEEE">
                <!--GRID ROW DEFENITIONS-->
                <Grid.RowDefinitions>
                    <RowDefinition Height="Auto"/>
                    <RowDefinition Height="*"/>
                </Grid.RowDefinitions>
        <!--MAIN SECTION-->
                <local:Menu>
                    <local:MenuItem Header="_File">
                        <local:MenuItem Header="_New">
                            <local:MenuItem Click="OnMenuClick">
                                <local:MenuItem.Header>
                                    <StackPanel Margin="-24,0,0,0" 
					Orientation="Horizontal">
                                        <Image VerticalAlignment="Center" 
					Width="16" Height="16" 
				       Source="Resources/Images/NewDocumentHS.png"/>
                                        <ContentControl Tag="AccessKey" 
					Margin="8,0,0,0" Content="_Project" 
					VerticalAlignment="Center"/>
                                    </StackPanel>
                                </local:MenuItem.Header>
                            </local:MenuItem>
                            <local:MenuItem Click="OnMenuClick" Header="Web Site"/>
                            <local:MenuItem Click="OnMenuClick" Header="File"/>
                            <local:MenuItem Click="OnMenuClick" 
				Header="Project From Existing Code"/>
                        </local:MenuItem>
                        <local:MenuItem Header="_Open">
                            <local:MenuItem KeyGesture="Shift+O" Click="OnMenuClick">
                                <local:MenuItem.Header>
                                    <StackPanel Margin="-24,0,0,0" 
					Orientation="Horizontal">
                                        <Image VerticalAlignment="Center" 
					Width="16" Height="16" 
					Source="Resources/Images/openHS.png"/>
                                        <TextBlock Margin="8,0,0,0" 
					Text="Project/Solution" 
					VerticalAlignment="Center"/>
                                    </StackPanel>
                                </local:MenuItem.Header>
                            </local:MenuItem>
                            <local:MenuItem Click="OnMenuClick" Header="Web Site"/>
                            <local:MenuItem Click="OnMenuClick" Header="File"/>
                            <local:MenuItem Click="OnMenuClick" Header="Convert"/>
                        </local:MenuItem>
                        <local:MenuItem Header="-"/>
                        <local:MenuItem Header="Add">
                            <local:MenuItem Click="OnMenuClick" Header="New Project"/>
                            <local:MenuItem Click="OnMenuClick" Header="Web Site"/>
                            <local:MenuItem Header="-"/>
                            <local:MenuItem Click="OnMenuClick" 
						Header="Existing Project"/>
                            <local:MenuItem Click="OnMenuClick" 
						Header="Existing Web Site"/>
                        </local:MenuItem>
                        <local:MenuItem Header="-"/>
                        <local:MenuItem KeyGesture="Shift+E" Click="OnMenuClick" 
							Header="Close"/>
                        <local:MenuItem Header="-"/>
                        <local:MenuItem Click="OnFullScreenClick" Header="Full _Screen"/>
                        <local:MenuItem Header="-"/>
                        <local:MenuItem Click="OnMenuClick" Header="Exit"/>
                    </local:MenuItem>
                    <local:MenuItem Header="_Edit">
                        <local:MenuItem Click="OnMenuClick">
                            <local:MenuItem.Header>
                                <StackPanel Margin="-24,0,0,0" Orientation="Horizontal">
                                    <Image VerticalAlignment="Center" 
				Width="16" Height="16" 
				Source="Resources/Images/Edit_UndoHS.png"/>
                                    <ContentControl Tag="AccessKey" 
				Margin="8,0,0,0" Content="_Undo" 
				VerticalAlignment="Center"/>
                                </StackPanel>
                            </local:MenuItem.Header>
                        </local:MenuItem>
                        <local:MenuItem Click="OnMenuClick">
                            <local:MenuItem.Header>
                                <StackPanel Margin="-24,0,0,0" Orientation="Horizontal">
                                    <Image VerticalAlignment="Center" 
				Width="16" Height="16" 
				Source="Resources/Images/Edit_RedoHS.png"/>
                                    <ContentControl Tag="AccessKey" 
				Margin="8,0,0,0" Content="_Redo" 
				VerticalAlignment="Center"/>
                                </StackPanel>
                            </local:MenuItem.Header>
                        </local:MenuItem>
                        <local:MenuItem Header="-"/>
                        <local:MenuItem KeyGesture="Shift+X" Click="OnMenuClick">
                            <local:MenuItem.Header>
                                <StackPanel Margin="-24,0,0,0" Orientation="Horizontal">
                                    <Image VerticalAlignment="Center" 
				Width="16" Height="16" 
				Source="Resources/Images/CutHS.png"/>
                                    <TextBlock Margin="8,0,0,0" Text="Cut" 
				VerticalAlignment="Center"/>
                                </StackPanel>
                            </local:MenuItem.Header>
                        </local:MenuItem>
                        <local:MenuItem KeyGesture="Shift+C" Click="OnMenuClick">
                            <local:MenuItem.Header>
                                <StackPanel Margin="-24,0,0,0" Orientation="Horizontal">
                                    <Image VerticalAlignment="Center" 
				Width="16" Height="16" 
				Source="Resources/Images/CopyHS.png"/>
                                    <TextBlock Margin="8,0,0,0" 
				Text="Copy" VerticalAlignment="Center"/>
                                </StackPanel>
                            </local:MenuItem.Header>
                        </local:MenuItem>
                        <local:MenuItem KeyGesture="Shift+V" Click="OnMenuClick">
                            <local:MenuItem.Header>
                                <StackPanel Margin="-24,0,0,0" Orientation="Horizontal">
                                    <Image VerticalAlignment="Center" 
				Width="16" Height="16" 
				Source="Resources/Images/PasteHS.png"/>
                                    <TextBlock  Margin="8,0,0,0" 
				Text="Paste" VerticalAlignment="Center"/>
                                </StackPanel>
                            </local:MenuItem.Header>
                        </local:MenuItem>
                    </local:MenuItem>
                    <local:MenuItem Header="_Help">
                        <local:MenuItem Click="OnMenuClick" Header="About"/>
                    </local:MenuItem>
                    <local:MenuItem Header="Deep Items _1">
                        <local:MenuItem Header="Item 1.1">
                            <local:MenuItem Header="Item 1.1.1">
                                <local:MenuItem Header="Item 1.1.1.1" 
				Click="OnMenuClick"/>
                                <local:MenuItem Header="Item 1.1.1.2" 
				Click="OnMenuClick"/>
                                <local:MenuItem Header="Item 1.1.1.3" 
				Click="OnMenuClick"/>
                            </local:MenuItem>
                            <local:MenuItem Header="Item 1.1.2">
                                <local:MenuItem Header="Item 1.1.2.1" 
				Click="OnMenuClick"/>
                                <local:MenuItem Header="Item 1.1.2.2" 
				Click="OnMenuClick"/>
                                <local:MenuItem Header="Item 1.1.2.3" 
				Click="OnMenuClick"/>
                            </local:MenuItem>
                        </local:MenuItem>
                        <local:MenuItem Header="Item 1.2" Click="OnMenuClick"/>
                        <local:MenuItem Header="Item 1.3" Click="OnMenuClick"/>
                        <local:MenuItem Header="Item 1.4" Click="OnMenuClick"/>
                    </local:MenuItem>
                    <local:MenuItem Header="Check Boxes">
                        <local:MenuItem x:Name="view_checked_1" IsChecked="True" 
				Click="OnMenuClick">
                            <local:MenuItem.Header>
                                <StackPanel Margin="-24,0,0,0" Orientation="Horizontal">
                                    <CheckBox IsChecked=
				"{Binding ElementName=view_checked_1, 
				Path=IsChecked, Mode=TwoWay}" Width="16" 
				Height="16" VerticalAlignment="Center"/>
                                    <ContentControl Tag="AccessKey" 
				Margin="8,0,0,0" Content="Status _bar" 
				VerticalAlignment="Center"/>
                                </StackPanel>
                            </local:MenuItem.Header>
                        </local:MenuItem>
                        <local:MenuItem Header="-"/>
                        <local:MenuItem x:Name="view_checked_gr_1" 
				GroupName="RadioButtonGroup_1" 
				IsChecked="True" Click="OnMenuClick">
                            <local:MenuItem.Header>
                                <StackPanel Margin="-24,0,0,0" Orientation="Horizontal">
                                    <RadioButton IsChecked=
				"{Binding ElementName=view_checked_gr_1, 
				Path=IsChecked, Mode=TwoWay}" Width="16" 
				Height="16" VerticalAlignment="Center"/>
                                    <ContentControl Tag="AccessKey" 
				Margin="8,0,0,0" Content="Full Mode" 
				VerticalAlignment="Center"/>
                                </StackPanel>
                            </local:MenuItem.Header>
                        </local:MenuItem>
                        <local:MenuItem x:Name="view_checked_gr_2" 
				GroupName="RadioButtonGroup_1" 
				IsChecked="False" Click="OnMenuClick">
                            <local:MenuItem.Header>
                                <StackPanel Margin="-24,0,0,0" Orientation="Horizontal">
                                    <RadioButton IsChecked=
				"{Binding ElementName=view_checked_gr_2, 
				Path=IsChecked, Mode=TwoWay}" Width="16" 
				Height="16" VerticalAlignment="Center"/>
                                    <ContentControl Tag="AccessKey" 
				Margin="8,0,0,0" Content="Compact Mode" 
				VerticalAlignment="Center"/>
                                </StackPanel>
                            </local:MenuItem.Header>
                        </local:MenuItem>
                        <local:MenuItem x:Name="view_checked_gr_3" 
				GroupName="RadioButtonGroup_1" 
				IsChecked="False" Click="OnMenuClick">
                            <local:MenuItem.Header>
                                <StackPanel Margin="-24,0,0,0" Orientation="Horizontal">
                                    <RadioButton IsChecked=
				"{Binding ElementName=view_checked_gr_3, 
				Path=IsChecked, Mode=TwoWay}" Width="16" 
				Height="16" VerticalAlignment="Center"/>
                                    <ContentControl Tag="AccessKey" 
				Margin="8,0,0,0" Content="Simple Mode" 
				VerticalAlignment="Center"/>
                                </StackPanel>
                            </local:MenuItem.Header>
                        </local:MenuItem>
                    </local:MenuItem>
                    <local:MenuItem Header="Item 3" Click="OnMenuClick">
                        <local:MenuItem Header="Item 3.1" Click="OnMenuClick"/>
                        <local:MenuItem Header="Item 3.2" Click="OnMenuClick"/>
                        <local:MenuItem Header="Item 3.3" Click="OnMenuClick"/>
                    </local:MenuItem>
                    <local:MenuItem Header="Item 4" Click="OnMenuClick">
                        <local:MenuItem Header="Item 4.1" Click="OnMenuClick"/>
                        <local:MenuItem Header="Item 4.2" Click="OnMenuClick"/>
                        <local:MenuItem Header="Item 4.3" Click="OnMenuClick"/>
                    </local:MenuItem>
                    <local:MenuItem Header="Item 5" Click="OnMenuClick">
                        <local:MenuItem Header="Item 5.1" Click="OnMenuClick"/>
                        <local:MenuItem Header="Item 5.2" Click="OnMenuClick"/>
                        <local:MenuItem Header="Item 5.3" Click="OnMenuClick"/>
                    </local:MenuItem>
                    <local:MenuItem Header="Item 6" Click="OnMenuClick">
                        <local:MenuItem Header="Item 6.1" Click="OnMenuClick"/>
                        <local:MenuItem Header="Item 6.2" Click="OnMenuClick"/>
                        <local:MenuItem Header="Item 6.3" Click="OnMenuClick"/>
                    </local:MenuItem>
                    <local:MenuItem Header="Item 7" Click="OnMenuClick">
                        <local:MenuItem Header="Item 7.1" Click="OnMenuClick"/>
                        <local:MenuItem Header="Item 7.2" Click="OnMenuClick"/>
                        <local:MenuItem Header="Item 7.3" Click="OnMenuClick"/>
                    </local:MenuItem>
                    <local:MenuItem Header="Item 8" Click="OnMenuClick">
                        <local:MenuItem Header="Item 8.1" Click="OnMenuClick"/>
                        <local:MenuItem Header="Item 8.2" Click="OnMenuClick"/>
                        <local:MenuItem Header="Item 8.3" Click="OnMenuClick"/>
                    </local:MenuItem>
                </local:Menu>
            </Grid>
        </Border>
    <TextBlock VerticalAlignment="Center" HorizontalAlignment="Center" 
		Foreground="Red" FontSize="16" x:Name="_click_text" Grid.Row="1" 
		Text="Nothing was clicked!"/>
  </Grid>
</UserControl>

All you have to do is put a couple of lines in XAML to see it in action:

XML
  <Grid  x:Name="LayoutRoot" Background="#FF75CEEE">
    <!--GRID ROW DEFENITIONS-->
    <Grid.RowDefinitions>
      <RowDefinition Height="25"/>
      <RowDefinition Height="*"/>
    </Grid.RowDefinitions>
    <!--MAIN SECTION-->
    <local:Menu Grid.Row="0" BorderBrush="#FF117396"
BorderThickness="2,2,2,2" Foreground="#FF1187B1" Margin="0,0,0,0">
      <MenuItem Header="File">
        <MenuItem Header="Open"/>
      </MenuItem>
    </local:Menu>
  <Grid

Well, I think that's it. If anybody needs help with the code, feel free to e-mail me, or just post a response.

License

This article, along with any associated source code and files, is licensed under The GNU General Public License (GPLv3)


Written By
Team Leader
Russian Federation Russian Federation
HIGHLIGHTS OF QUALIFICATIONS:
8 years experience in development for custom payment and transaction banking system based on smart cards
15 years of MS .NET platform development experience
Specializing in the distributed server applications and custom UI component development for Windows-based platforms
Strong knowledge and skills including:
OOA/OOD, and multithreaded programming experience
MFC v4.x/v7.x. MS API’s (WIN32)
Windows and Web GUI components development
COM/ COM+ distributed applications development
MS Visual Studio 2002-2008, Visual C++ v6.0-v9.0, Visual C# 1.1-3.5
MS .NET Frameworks 1.0 - 3.5, MS Silverlight v2.0, JavaScript
XML,XSLT,XSD

Comments and Discussions

 
QuestionIs there a support to add a Hyper link as the menu item. Pin
Padmaja Sagi27-Apr-11 2:28
Padmaja Sagi27-Apr-11 2:28 
AnswerRe: Is there a support to add a Hyper link as the menu item. Pin
Alexei Prokudin27-Apr-11 3:22
Alexei Prokudin27-Apr-11 3:22 
AnswerRe: Is there a support to add a Hyper link as the menu item. Pin
Alexei Prokudin27-Apr-11 3:28
Alexei Prokudin27-Apr-11 3:28 
GeneralVisibility via Code-Behind Pin
James Cow4-Apr-11 11:36
James Cow4-Apr-11 11:36 
QuestionDropdownMenu Application Hang Pin
noblefranklin7-Aug-10 23:39
noblefranklin7-Aug-10 23:39 
GeneralDropdownMenu Silverlight Pin
Suresh Rajamani29-Mar-10 18:51
Suresh Rajamani29-Mar-10 18:51 
GeneralAdd image at Runtime Pin
ayanc7219-Mar-10 23:49
ayanc7219-Mar-10 23:49 
QuestionRTL Support?? Pin
Ali Taghvajou10-Mar-10 13:46
professionalAli Taghvajou10-Mar-10 13:46 
QuestionDatabinding Pin
Member 38957734-Mar-10 4:37
Member 38957734-Mar-10 4:37 
AnswerRe: Databinding Pin
Alexei Prokudin15-Mar-10 4:01
Alexei Prokudin15-Mar-10 4:01 
GeneralMenu doesn't open Pin
EEJDX2-Mar-10 13:55
EEJDX2-Mar-10 13:55 
GeneralPopup from Menu Bar Pin
73amit2-Feb-10 19:47
73amit2-Feb-10 19:47 
GeneralRe: Popup from Menu Bar Pin
Alexei Prokudin5-Feb-10 22:29
Alexei Prokudin5-Feb-10 22:29 
GeneralMy vote of 2 Pin
Member 183522721-Dec-09 2:48
Member 183522721-Dec-09 2:48 
GeneralRe: My vote of 2 Pin
Alexei Prokudin5-Feb-10 22:34
Alexei Prokudin5-Feb-10 22:34 
GeneralXamlParseException Pin
Member 183522718-Dec-09 5:14
Member 183522718-Dec-09 5:14 
GeneralRe: XamlParseException Pin
Alexei Prokudin5-Feb-10 22:38
Alexei Prokudin5-Feb-10 22:38 
GeneralRe: XamlParseException Pin
Member 18352279-Feb-10 2:48
Member 18352279-Feb-10 2:48 
GeneralSilverlight Library Pin
A. Bioli9-Nov-09 11:46
A. Bioli9-Nov-09 11:46 
I tried (with no luck) to generate a Silverlight library starting from your code: I think this menu could be much more interesting if available in a separate library. Could you make it or give us just some hint on how to make it?
Thanks in advance
Andrea
GeneralRe: Silverlight Library Pin
Alexei Prokudin9-Nov-09 19:56
Alexei Prokudin9-Nov-09 19:56 
QuestionParticipation Pin
aaabor3-Sep-09 4:45
aaabor3-Sep-09 4:45 
AnswerRe: Participation Pin
Alexei Prokudin3-Sep-09 5:54
Alexei Prokudin3-Sep-09 5:54 
GeneralArgumentException Pin
alecs312-Aug-09 4:12
alecs312-Aug-09 4:12 
GeneralRe: ArgumentException Pin
Alexei Prokudin12-Aug-09 9:03
Alexei Prokudin12-Aug-09 9:03 
GeneralRe: ArgumentException [modified] Pin
Alexei Prokudin12-Aug-09 9:30
Alexei Prokudin12-Aug-09 9:30 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.