Wpf – MVVM binding command to contextmenu item

mvvmwpf

I'm trying to bind a command to a menuitem in WPF. I'm using the same method that's been working for all my other command bindings, but I can't figure out why it doesn't work here.

I'm currently binding my commands like this:

Command = "{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type UserControl}}, Path=DataContext.MyCommand}"

This is where it goes wrong (this is inside a UserControl)

<Button Height="40" Margin="0,2,0,0" CommandParameter="{Binding Name}" 
                        Command = "{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type UserControl}}, Path=DataContext.ConnectCommand}">

     <Button.ContextMenu>
         <ContextMenu>
             <MenuItem Header="Remove" CommandParameter="{Binding Name}"
                                      Command="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type UserControl}}, Path=DataContext.RemoveCommand}"/>
         </ContextMenu>
     </Button.ContextMenu>
     ...

The first command binding works like it should, but the second one refuses to do anything.
I've tried changing the ancestor level and naming my Control to access it through ElementName instead of RelativeSource, but still no change. It keeps saying "Cannot find source for binding with reference…"

What am I missing?

Best Answer

(Edit) Since you mentioned this is in an ItemsControl's template, things are different:

1) Get the BindingProxy class from this blog (and read the blog, as this is interesting information): How to bind to data when the DataContext is not inherited.

Basically the elements in the ItemsControl (or ContextMenu) are not part of the visual or logical tree, and therefore cannot find the DataContext of your UserControl. My apologies for not writing more on this here, but the author has done a good job explaining it step by step, so there's no way I could give a complete explanation in just a few lines.

2) Do something like this: (you may have to adapt it a bit to make it work in your control):

a. This will give you access to the UserControl DataContext using a StaticResource:

<UserControl.Resources>
<BindingProxy
  x:Key="DataContextProxy"
  Data="{Binding}" />
</UserControl.Resources>

b. This uses the DataContextProxy defined in (a):

<Button.ContextMenu>
 <ContextMenu>
     <MenuItem Header="Remove" CommandParameter="{Binding Name}"
         Command="{Binding Path=Data.RemoveCommand, Source={StaticResource DataContextProxy}}"/>
 </ContextMenu>

This has worked for us in things like trees and datagrids.

Related Topic