CanExecute not raised when context menu opens

720 Views Asked by At

I know there are a handful of related questions but none of those helped me finding the issue.

Most answers suggest to implement CanExecuteChanged as shown in this answer. Well, that's not the solution to my problem. I've got an implementation of RelayCommand similar to Josh Smith's implemenation. (Similar, because our implementation adds more details but the core implementation is the same.)

While searching the Internet I also learned that if there is no focused element, the routing will stop at the ContextMenu and wouldn't reach the MenuItem. A solution that would help in that case is shown here.
However, I checked with Snoop if there really isn't any focused element and learned this is not the issue. And the fix didn't help anyway.
Besides, I simulated that issue in a test project and was able to fix it. So the fix generally works, it's just not helping me. I think there's still a chance, however, that I have to adapt the fix slightly to get it working. I tried MyControl instead of ContextMenu as AncestorType and I tried PlacementTarget.Tag instead of just PlacementTarget as Path but I wouldn't know what else to try to get it working (assuming that this is the bug).

Funny enough, it even doesn't work when I call CommandManager.InvalidateRequerySuggested() manually. I added a command that is raised on ContextMenuOpening. I thought that this would force the CanExecute to be executed but it seems I'm mistaken.

So, I'm now looking for further reasons why a CanExecute handler isn't raised when a ContextMenu is opened and how I would fix that.

Here's my XAML code (including EventTrigger for ContextMenuOpening):

<MyControl>
  <MyControl.ContextMenu>
    <ContextMenu>
      <MenuItem Header="..."
                Command="{Binding MyCommand}"
                CommandParameter="{Binding}"
                CommandTarget="{Binding Path=PlacementTarget,
                  RelativeSource={RelativeSource
                    AncestorType={x:Type ContextMenu}}}"/>
    </ContextMenu>
  </MyControl.ContextMenu>
  <i:Interaction.Triggers>
    <i:EventTrigger EventName="ContextMenuOpening">
      <i:InvokeCommandAction Command="{Binding OnContextMenuOpening}" />
    </i:EventTrigger>
  </i:Interaction.Triggers>
</MyControl>

Here's the definition of MyCommand and the (Can)Execute handlers:

internal static readonly ICommandEx MyCommand = 
  new RelayCommand(OnMyCommand, OnCanMyCommand);

private static void OnMyCommand(object parameter) { ... }

private static bool OnCanMyCommand(object parameter) { ... }

Here's my OnContextMenuOpening handler where I tried to force MyCommand's CanExecute to be raised:

private static void OnContextMenuOpening(object parameter)
{
  CommandManager.InvalidateRequerySuggested();
}
1

There are 1 best solutions below

0
l33t On

You are incorrectly listening on OnContextMenuOpening on the ContextMenu control. It will never fire! Instead, listen on this very event on your MyControl control.