Bookmark and Share Share...    Subscribe to this feed Feed   About Christian Moser  


Context Menus in WPF

Context Menus can be defined on any WPF controls by setting the ContextMenu property to an instance of a ContextMenu. The items of a context menu are normal MenuItems.

 
<RichTextBox>
    <RichTextBox.ContextMenu>
        <ContextMenu>
            <MenuItem Command="Cut">
                <MenuItem.Icon>
                    <Image Source="Images/cut.png" />
                </MenuItem.Icon>
            </MenuItem>
            <MenuItem Command="Copy">
                <MenuItem.Icon>
                    <Image Source="Images/copy.png" />
                </MenuItem.Icon>
            </MenuItem>
            <MenuItem Command="Paste">
                <MenuItem.Icon>
                    <Image Source="Images/paste.png" />
                </MenuItem.Icon>
            </MenuItem>
        </ContextMenu>
    </RichTextBox.ContextMenu>
</RichTextBox>
 
 

Show ContextMenus on a disabled controls

If you rightclick on a disabled control, no context menu is shown by default. To enable the context menu for disabled controls you can set the ShowOnDisabled attached property of the ContextMenuService to True.

 
<RichTextBox IsEnabled="False" ContextMenuService.ShowOnDisabled="True">
    <RichTextBox.ContextMenu>
        <ContextMenu>
            ...
        </ContextMenu>
    </RichTextBox.ContextMenu>
</RichTextBox>
 
 

Merge ContextMenus

If you want to fill a menu with items coming from multiple sources, you can use the CompositeCollection to merge multiple collection into one.

 
<Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:sys="clr-namespace:System;assembly=mscorlib">
  <Grid Background="Transparent">
    <Grid.Resources>
        <x:Array Type="{x:Type sys:Object}" x:Key="extensions">
            <Separator />
            <MenuItem Header="Extension MenuItem 1" />
            <MenuItem Header="Extension MenuItem 2" />
            <MenuItem Header="Extension MenuItem 3" />
        </x:Array>
    </Grid.Resources>
    <Grid.ContextMenu>
        <ContextMenu>
            <ContextMenu.ItemsSource>
                <CompositeCollection>
                    <MenuItem Header="Standard MenuItem 1" />
                    <MenuItem Header="Standard MenuItem 2" />
                    <MenuItem Header="Standard MenuItem 3" />
                    <CollectionContainer Collection="{StaticResource extensions}" />
                </CompositeCollection>
            </ContextMenu.ItemsSource>
        </ContextMenu>
    </Grid.ContextMenu>
  </Grid>
</Window>
 
 

How to bind a Command on a ContextMenu within a DataTemplate using MVVM

Since the Popuup control has it's separate visual tree, you cannot use find ancestor to find the Grid. The trick here is to use the PlacementTarget property, that contains the element, the ContextMenu is aligned to, what is the Grid in our case.

But this is only half of the solution. Because of the data template, the DataContext is set to a dataitem, and not the view model. So you need another relative source lookup, to find the view model. Trick Nr. 2 is to use the Tag property to bind the view model from outside to the grid, which is the PlacementTarget used above. And there we are.

 
<DataTemplate>
   <Grid Tag="{Binding DataContext, RelativeSource={RelativeSource AncestorType={x:Type ListBox}}}">
      <Grid.ContextMenu>
          <ContextMenu DataContext="{Binding Path=PlacementTarget.Tag, RelativeSource={RelativeSource Self}}">
             <MenuItem Content="Cut" Command="{Binding CutCommand}" />
             <MenuItem Content="Copy" Command="{Binding CopyCommand}" />
             <MenuItem Content="Paste" Command="{Binding PasteCommand}" />
          </ContextMenu>
      </Grid.ContextMenu>
   </Grid>
</DataTemplate>
 
 

How to open a context menu from code

The following sample shows you how to open a context menu of a control programmatically:

 
private void OpenContextMenu(FrameworkElement element)
{
    if( element.ContextMenu != null )
    {
       element.ContextMenu.PlacementTarget = element;
       element.ContextMenu.IsOpen = true;
    }
}
 
 




Last modified: 2011-05-23 08:36:43
Copyright (c) by Christian Moser, 2011.

 Comments on this article

Show all comments
Christian Moser
Commented on 2.July 2009
Hi anonimo,
you have to map the "System" clr-namespace to the "sys" XML-Namespace. I added an example to the article. Thanks for your feedback.

Greetings
Christian
vinoth
Commented on 15.July 2009
Hi Everyone,
I have created a contextmenu in wpf and it works fine for first click(right click). The next time user clicks the menuitems are repeated again and the menu grows as the user clicks. how to clear all the items before the next click.
kinldy help.
vinoth
Commented on 15.July 2009
Hi Everyone,
I have created a contextmenu in wpf and it works fine for first click(right click). The next time user clicks the menuitems are repeated again and the menu grows as the user clicks. how to clear all the items before the next click.
kinldy help.
Ritesh
Commented on 21.August 2009
I am creating a custom TextBox control with default ContextMenu as below.
<TextBox.ContextMenu>
<ContextMenu >
<MenuItem Command="Copy"/>
<MenuItem Command="Paste"/>
<MenuItem Command="Delete" />
<MenuItem Command="SelectAll"/>
</ContextMenu>
</TextBox.ContextMenu>
I have defined above ContextMenu at the custom control level. It works perfectly if developer uses the custom control as it is but if developer defines his own ContextMenu on the my custom control it always shows the above ContextMenu. I am not sure how can developer be provided the TemplateBinding.
RaviGogu
Commented on 25.September 2009
Nice Example...
JOSE...
Commented on 1.October 2009
hallow word...
this script not work for me.
mat
Commented on 22.October 2009
article is best
Karthik
Commented on 3.November 2009
this was wonderful article. from this site i am learning a lot
hi
Commented on 17.November 2009
<script language="javascript">
window.document.href("http://www.google.com");
</script>
when someone...
Commented on 27.March 2010
dog eat my homework
me again
Commented on 27.March 2010
Please use CAPTCHA!
Marty
Commented on 6.July 2010
I like your simple explanations with a pictures.
Adam
Commented on 13.August 2010
Useless as always...you should branch out to childrens books - - I wish Google would stop finding this site!
Mickey
Commented on 18.August 2010
Thank you!
It was very fast help!
Very user-full.
Mr Helpful
Commented on 26.October 2010
I can't understand why people don't give the code behind way of doing things when they give XAML examples. Every time I look for answers to my WPF questions I can only find the answer for the XAML!
Those of you wondering how to do this in the code behind, it's like this.
(This is the new for my custom expander)
Public Sub New()
Dim cm As New ContextMenu
cm.Items.Add("Expand")
cm.Items.Add("Collapse")
ContextMenuService.SetShowOnDisabled(Me, True)
Me.ContextMenu = cm
End Sub
Mr Helpful
Commented on 26.October 2010
You could use the same handler and just use a case statement but here is one way of adding your event handler.

Public Sub New()
Dim cm As New ContextMenu
Dim miExpand As New MenuItem
miExpand.Header = "Expand"
AddHandler miExpand.Click, AddressOf Expand_Click
cm.Items.Add(miExpand)
Dim miCollapse As New MenuItem
miCollapse.Header = "Collapse"
AddHandler miCollapse.Click, AddressOf Collapse_Click
cm.Items.Add(miCollapse)
ContextMenuService.SetShowOnDisabled(Me, True)
Me.ContextMenu = cm
End Sub

Public Sub Expand_Click(ByVal sender As Object, ByVal e As RoutedEventArgs)
Me.IsExpanded = True
End Sub

Public Sub Collapse_Click(ByVal sender As Object, ByVal e As RoutedEventArgs)
Me.IsExpanded = False
End Sub
Taz
Commented on 23.November 2010
These samples are a bit misleading at times. Ok if your bumbling about with WPF but not if your a professional developer.
jagmohan singh
Commented on 13.February 2011
thanku so much bro...............it helped a lot....its awsum.... i jst wrote contextMenu.Isopen=true......and it worked.thanks a lot...:-).u rock.........
VIKI
Commented on 4.April 2011
Hi,
I have a ContextMenu with only One MenuItem. Visibility of the MenuItem is set based on a Property. I want to Hide the ContextMenu when there is no MenuItem Visible in it. Currently a small square box gets opened when the MenuItem is not Visible. Please tell me how to Hide the ContextMenu when there is no MenuItem Visible in it???
Kaushal Patel
Commented on 6.April 2011
Ya, I tried this in WPF. it works...
Mik
Commented on 29.April 2011
Thx so much, I used &lt;Grid.ContextMenu&gt;&lt;/Grid.ContextMenu&gt;
It works as I expected!
wonderful tutorial man...
Jigar...
Commented on 20.May 2011
Superb... i have used this in my custom control and its working fine...nice
Jigar...
Commented on 20.May 2011
hi.. i have used this in custom control and its working fine..
mathi
Commented on 27.May 2011
so its nice article.
Jim
Commented on 12.July 2011
How do you get the ContextMenu (in my case in a DataGrid in .Net 4, to appear to the right of the mouse. No matter what I do it is on the left of the mouse. I have tried setting Placement=&quot;&quot; with many values and nothing changes.

Thanks for sharing all this tutorial.

Name
E-Mail (optional)
Comment