One of the most common question asked on various WPF Forums is “How can we have Submenu or nested menuitems in WPF Toolbar”. Toolbar in WPF doesn’t show sub menuitems on mouseover or click event. So following code for Toolbar doesn’t work.
<ToolBar Name="ToolBar1" Height="25">
<!-- Regular Items -->
<Button Content="Item A"/>
<Button Content="Item B"/>
<!-- SubItems Menu For Special Items -->
<MenuItem Header="Special Items">
<MenuItem Header="Special Item A" />
<MenuItem Header="Special Item B" />
</MenuItem>
</ToolBar>
So I decide to create my own custom control which Inherits MenuItem and can handle mouseover or click event. MenuItem has a property IsSubMenuOpen which we can use to open submenu for MenuItem. Another useful property is StayOpenOnClick, which if we set to False then whenever user click outside of MenuItem, submenu will automatically get closed.
Imports System.Windows.Controls.Primitives
Public Class ToolBarMenuItem
Inherits System.Windows.Controls.MenuItem
Shared Sub New()
'This OverrideMetadata call tells the system that this element wants to provide a style that is different than its base class.
'This style is defined in themes\generic.xaml
DefaultStyleKeyProperty.OverrideMetadata(GetType(ToolBarMenuItem), New FrameworkPropertyMetadata(GetType(ToolBarMenuItem)))
End Sub
Public Enum PlacementMode
Bottom = 0
Top = 1
Right = 2
Left = 3
End Enum
Public Shared ReadOnly SubMenuPlacementModeProperty As DependencyProperty = DependencyProperty.Register("SubMenuPlacementMode", GetType(PlacementMode), GetType(ToolBarMenuItem), New FrameworkPropertyMetadata(PlacementMode.Bottom))
Public Property SubMenuPlacementMode As PlacementMode
Get
Return GetValue(SubMenuPlacementModeProperty)
End Get
Set(ByVal value As PlacementMode)
SetValue(SubMenuPlacementModeProperty, value)
End Set
End Property
Private Sub ToolBarMenuItem_Click(ByVal sender As Object, ByVal e As System.Windows.RoutedEventArgs) Handles Me.Click
Me.IsSubmenuOpen = False
End Sub
Private Sub ToolBarMenuItem_MouseLeave(ByVal sender As Object, ByVal e As System.Windows.Input.MouseEventArgs) Handles Me.MouseLeave
Me.IsSubmenuOpen = False
End Sub
Private Sub ToolBarMenuItem_PreviewMouseLeftButtonDown(ByVal sender As Object, ByVal e As System.Windows.Input.MouseButtonEventArgs) Handles Me.PreviewMouseLeftButtonDown
If Me.IsSubmenuOpen = False Then
Me.IsSubmenuOpen = True
Me.StaysOpenOnClick = False
End If
End Sub
End Class
We also need to add a XAML Code which contain Style for our custom control which is available in the source at the end of the article.
We can use the above custom control in following way.
<Window x:Class="MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:my="clr-namespace:ToolBarMenuItemDemo"
Title="NestedToolBarItem Demo" Height="350" Width="525" Background="Aquamarine">
<Grid VerticalAlignment="Top">
<ToolBar Name="ToolBar1" Height="25" >
<!--Regular Items-->
<Button Content="Item A"/>
<Button Content="Item B"/>
<!--SubItems Menu For Special Items-->
<my:ToolBarMenuItem Header="Special Items" VerticalContentAlignment="Center" SubMenuPlacementMode="Bottom">
<MenuItem Header="Special Item 1" />
<MenuItem Header="Special Item 2" />
</my:ToolBarMenuItem>
</ToolBar>
</Grid>
</Window>
Download Source Code