65.9K
CodeProject is changing. Read more.
Home

WPF: Context Menu on List Item

starIconstarIconstarIconstarIconstarIcon

5.00/5 (7 votes)

May 12, 2010

Apache

1 min read

viewsIcon

47933

WPF: Context Menu on List Item

I am using WPF and MVVM. I have a Window and a view model attached to it via Datacontext. The window has a listbox, and its items have context menu. I am using DelegateCommand in my view model, and I want to bind a menu items in the context menu to this command.

The first problem is that by default the menu item is bound to the DataContext of the list box item, which may or may not have knowledge of the whole view model.

The second problem is that context menu is not part of the visual tree, so referring to the main window via FindAncestor or ElementName=... will not work.

You can get to the object immediately containing the context menu via the PlacementTarget property, but then you will need an ancestor of this object (“window”), and there is no built-in way to find an ancestor of a property.

An (almost) working solution that I found on the Internet after hours of search was to store the data context some property of the PlacementTarget – they used Tag for this purpose.

The “almost” part lies in the fact that if your command has CanExecute() method, the command parameter passed to it is sometimes null (see here).

<Window Name="MainWindow" ...>
    <Grid>
        <ListBox ItemsSource="{Binding Items}">
            <ListBox.ItemTemplate>
                <DataTemplate>
                    <StackPanel Orientation="Horizontal"
                               Tag="{Binding DataContext, ElementName=MainWindow}">
			...
                        <StackPanel.ContextMenu>
                             <MenuItem Header="do it"
    Command="{Binding PlacementTarget.Tag.MyCommand, 
	RelativeSource={RelativeSource AncestorType=ContextMenu}}"
    CommandParameter="{Binding}">
                        </StackPanel.ContextMenu>
                    </StackPanel>
                </DataTemplate>
            </ListBox.ItemTemplate>
        </ListBox>
    </Grid>
</Window>