ContextMenu on button click not firing command

button, contextmenu, onclick, wpf

Solution

`PlacementTarget` is `null` when you manually set `ContextMenu.IsOpen` property because it is set to actual value only once it's open by right clicking on target control. (`PopUpService` class is responsible for setting this value to actual target).

Since `PlacementTarget` is `null` in case when you open it via `Storyboard`, binding is not able to resolve actual command it's binded to.

So, issue is you need to pass on the `DataContext` of `Button` to the `MenuItem` so that binding can be resolved. (`MenuItem` are not is same visual tree as that of button). That can be achieved via two ways:

Using `x:Reference` (available in WPF 4.0 and higher) but you need to declare dummy control so that it can be referenced to get `DataContext` with `Visibility` set to `Collapsed`.

<FrameworkElement x:Name="dummyControl" Visibility="Collapsed"/>
   <Button Width="100" Height="30" Name="cmButton">
      <Button.ContextMenu>
         <ContextMenu>
           <MenuItem Header="New Layout Element..."
                     Command="{Binding Path=DataContext.SubmitBtn,
                                       Source={x:Reference dummyControl}}" />
         </ContextMenu>
      </Button.ContextMenu>
   </Button>

Another interesting thing is `Freezable` objects inherit `DataContext` even if they don't lie in `VisualTree` so we can use this feature to overcome situations where we need to inherit `DataContext`.

First we need to `create class inheriting from Freezable` and exposing DP which can be bind to:

public class BindingProxy : Freezable
{
    #region Overrides of Freezable

    protected override Freezable CreateInstanceCore()
    {
        return new BindingProxy();
    }

    #endregion

    public object Data
    {
        get { return (object)GetValue(DataProperty); }
        set { SetValue(DataProperty, value); }
    }

    public static readonly DependencyProperty DataProperty =
     DependencyProperty.Register("Data", typeof(object), typeof(BindingProxy));
}

Now we can use it in XAML like this:

<Button Width="100" Height="30" Name="cmButton">
    <Button.Resources>
        <local:BindingProxy x:Key="proxy" Data="{Binding}"/>
    </Button.Resources>
    <Button.ContextMenu>
        <ContextMenu>
            <MenuItem Header="New Layout Element..."
                      Command="{Binding Path=Data.SubmitBtn,
                                        Source={StaticResource proxy}}" />
        </ContextMenu>
    </Button.ContextMenu>
</Button>

Problem

Here is a problem. I am displaying context menu on a button click and the menu command is bind to `ICommand` in the view model. Menu is displaying on the button click as well as on the right click. The problem is menu click is not firing when I click button and then click context menu, but I can confirm that menu is working when I right click on button and then click on menu. ``` <Button Grid.Row="3" Width="500" Height="30" Name="cmButton" > Button with Context Menu <Button.ContextMenu> <ContextMenu DataContext="{Binding Path=PlacementTarget.DataContext, RelativeSource={RelativeSource Mode=Self}}" > <MenuItem DataContext="{Binding}" Header="New Layout Element..." Command="{Binding Path=SubmitBtn}" /> </ContextMenu> </Button.ContextMenu> <Button.Style> <Style TargetType="{x:Type Button}"> <Style.Triggers> <EventTrigger RoutedEvent="Click"> <EventTrigger.Actions> <BeginStoryboard> <Storyboard> <BooleanAnimationUsingKeyFrames Storyboard.TargetProperty="ContextMenu.IsOpen"> <DiscreteBooleanKeyFrame KeyTime="0:0:0" Value="True"/> </BooleanAnimationUsingKeyFrames> </Storyboard> </BeginStoryboard> </EventTrigger.Actions> </EventTrigger> </Style.Triggers> </Style> </Button.Style> </Button> ``` I can confirm there is nothing wrong in my view model because command is firing when I do right click on button then click on context menu.

Original source