How would you like your WPF application to have a Context Menu like this:

Well, It is not so hard. Here is how you do it:
This is the Context Menu that was defined for this example:
1: <TextBox Text="Right click Me" Margin="25">
2: <TextBox.ContextMenu>
3: <ContextMenu Style="{StaticResource ContextMenuStyle}">
4: <MenuItem x:Name="MenuItem1" Header="Cut" Command="Cut"
5: Style="{StaticResource ContextMenuItem}"
6: Tag="pack://application:,,,/ContextMenu;Component/Cut.png">
7: </MenuItem>
8: <MenuItem x:Name="MenuItem2" Header="Copy" Command="Copy"
9: Style="{StaticResource ContextMenuItem}"
10: Tag="pack://application:,,,/ContextMenu;Component/Copy.png">
11: </MenuItem>
12: <MenuItem x:Name="MenuItem3" Header="Paste" Command="Paste"
13: Style="{StaticResource ContextMenuItem}"
14: Tag="pack://application:,,,/ContextMenu;Component/Paste.png">
15: </MenuItem>
16: <MenuItem x:Name="MenuItem4" Header="Delete" Command="Delete"
17: Style="{StaticResource ContextMenuItem}"
18: Tag="pack://application:,,,/ContextMenu;Component/Delete.png">
19: </MenuItem>
20: </ContextMenu>
21: </TextBox.ContextMenu>
22: </TextBox>
As you can see both the Context Menu and The MenuItem have styles, and this is where all the magic happens :).
The context menu style is very simple:
1: <Style TargetType="{x:Type ContextMenu}" x:Key="ContextMenuStyle">
2: <Setter Property="BorderBrush"
3: Value="{StaticResource ContextMenuBorderColor}">
4: </Setter>
5: <Setter Property="BorderThickness"
6: Value="1">
7: </Setter>
8: <Setter Property="Background"
9: Value="{StaticResource ContextMenuBackgroundColor}">
10: </Setter>
11: <Setter Property="Padding"
12: Value="-1">
13: </Setter>
14: <Setter Property="FontSize"
15: Value="13">
16: </Setter>
17: </Style>
The real work is with the MenuItem Style. It is basically a ControlTemplate for the MenuItem where I use an Image and a TextBlock to design the Item.
Ok so here is the code. You can download the sample project to check it all out.
1: <Style TargetType="{x:Type MenuItem}" x:Key="ContextMenuItem">
2: <Setter Property="MenuItem.Template">
3: <Setter.Value>
4: <ControlTemplate>
5: <Border HorizontalAlignment="Stretch" x:Name="Root" >
6: <Grid>
7: <Grid.ColumnDefinitions>
8: <ColumnDefinition Width="26"></ColumnDefinition>
9: <ColumnDefinition Width="130"></ColumnDefinition>
10: </Grid.ColumnDefinitions>
11: <Border HorizontalAlignment="Stretch"
12: VerticalAlignment="Stretch"
13: x:Name="ImageWrapper"
14: Background="{StaticResource MenuItemImageColor}"
15: Grid.
Column="0">
16: <Image Width="24" Height="24" Margin="1"
17: Source="{TemplateBinding Property=MenuItem.Tag,
18: Converter={x:Static data:URI2ImageConverter.Instance}}">
19: </Image>
20: </Border>
21: <Border Grid.Column="1" x:Name="NameWrapper"
22: HorizontalAlignment="Stretch" Padding="1,0,2,0">
23: <TextBlock Text="{TemplateBinding MenuItem.Header}"
24: x:Name="Name"
25: Foreground="{StaticResource MenuItemTextColor}"
26: VerticalAlignment="Center"
27: HorizontalAlignment="Stretch"
28: Margin="2,0,0,0" ></TextBlock>
29: </Border>
30: <Border x:Name="DisabledOverlay"
31: HorizontalAlignment="Stretch"
32: VerticalAlignment="Stretch"
33: Grid.Column="0" Grid.ColumnSpan="2"
34: Background="{StaticResource ContextMenuBorderColor}"
35: Opacity="0" >
36: </Border>
37: </Grid>
38: </Border>
39: <ControlTemplate.Triggers>
40: <Trigger Property="IsMouseOver" Value="true" SourceName="Root">
41: <Trigger.Setters>
42: <Setter Property="Background"
43: TargetName="NameWrapper"
44: Value="{StaticResource MenuItemTextColor}" >
45: </Setter>
46: <Setter Property="Background"
47: TargetName="Name"
48: Value="{StaticResource MenuItemTextColor}" >
49: </Setter>
50: <Setter Property="Foreground"
51: TargetName="Name"
52: Value="{StaticResource MenuItemHoverTextColor}" >
53: </Setter>
54: <Setter Property="Background"
55: TargetName="ImageWrapper"
56: Value="{StaticResource MenuItemTextColor}" >
57: </Setter>
58: </Trigger.Setters>
59: </Trigger>
60: <Trigger Property="IsEnabled" Value="false" SourceName="Root">
61: <Trigger.Setters>
62: <Setter Property="Opacity"
63: TargetName="DisabledOverlay"
64: Value="0.7" ></Setter>
65: <Setter Property="Foreground"
66: TargetName="Name"
67: Value="{StaticResource ContextMenuBorderColor}" >
68: </Setter>
69: </Trigger.Setters>
70: </Trigger>
71: </ControlTemplate.Triggers>
72: </ControlTemplate>
73: </Setter.Value>
74: </Setter>
75: </Style>
Some of you will as why is the Converter a Singleton, There is a good reason for that and I will explain it in a post later on.
To download the Sample Project Subscribe to our feed and get access to our Freebies Page
If you have any questions please comment.
Enjoy
Amit
Update: Take alook at the better WPF Custom ContextMenu
Michael Said on Jun 20, 2008 :
Good work, Amit.
I think that this post http://weblogs.asp.net/okloeten/archive/2007/11/14/5149692.aspx may complete the picture.