WPF custom command in context menu are disabled until any button clicked

commandwpf

I have a custom command and I try to execute them from the context menu, but they are always displayed as disabled unless I click any button on the UI (buttons do not have anything to do with commands).

After clicking a button, commands start to be displayed correctly (when they are unavailable they get disabled and enabled if available).

Edit: it turns out that it is not the button click which makes command work correctly, but button or other controls in focus (e.g. if I tab into a control this also enables my commands).

Here is the code for commands:

<Window.InputBindings>
    <KeyBinding Command="{x:Static local:MainWindow.Quit}" Key="Q" Modifiers="Ctrl"/>
    <KeyBinding Command="{x:Static local:MainWindow.Disconnect}" Key="D" Modifiers="Ctrl"/>
</Window.InputBindings>

<Window.ContextMenu>
    <ContextMenu Opacity="95">
        <MenuItem Header="Quit Application                  Ctrl + Q"   Command="{x:Static local:MainWindow.Quit}"/>
        <MenuItem Header="Disconnect from the pump   Ctrl + D" Command="{x:Static local:MainWindow.Disconnect}"/>
    </ContextMenu>
</Window.ContextMenu>

Here is the commands CanExecuteMethod:

public static RoutedCommand Quit = new RoutedCommand();   

private void QuitCanExecute(object sender, CanExecuteRoutedEventArgs e)
     {
      e.CanExecute = true;
      e.Handled = true;
     }

Best Answer

This issue is due to the ContextMenu being on a separate Visual and Logical Tree to that of the Window and its Controls.

For anyone still looking for an answer to this issue - After trawling the internet I have found the most effective answer to be to include the following in any declaration of a MenuItem that needs its commands to be heard by it's "owner".

In layman's terms; if you want the commands of your context menu to be heard by the thing you're right clicking on. Add this code:

CommandTarget="{Binding Path=PlacementTarget,
                        RelativeSource={RelativeSource AncestorType=ContextMenu}
               }"

Example:

    <ContextMenu>
        <MenuItem Header="Close" Command="Application.Close"
                  CommandTarget="{Binding Path=PlacementTarget, RelativeSource={RelativeSource AncestorType=ContextMenu}}" />
    </ContextMenu>

This will also work within Templates (something I found a lot of another solutions not to support). Here is an explanation of the meaning of the statement taken from elsewhere (I'm appalling at explaining things):

Every FrameworkElement has a DataContext that is an arbitrary object. The default source for a data binding is that DataContext. You can use RelativeSource.Self to change the source for a binding to the FrameworkElement itself instead of its DataContext. So the RelativeSource part just moves you "up one level" from the DataContext of the FrameworkElement to the FrameworkElement itself. Once you are at the FrameworkElement you can specify a path to any of its properties. If the FrameworkElement is a Popup, it will have a PlacementTarget property that is the other FrameworkElement that the Popup is positioned relative to.

In short, if you have a Popup placed relative to a TextBox for example, that expression sets the DataContext of the Popup to the TextBox and as a result {Binding Text} somewhere in the body of the Popup would bind to the text of the TextBox.

I honestly hope that this information saves someone who's new to WPF the headache I've gone through this weekend... though it did teach me a lot!

Related Topic