Pregunta

I am trying to bind commands to various MenuItems in a ContextMenu that I will be hooking up with a Button. But for this, I am defining all commands as static in a class that I have imported in my ResourceDictionary.

public class DesignerCanvas{
    ....
    public static RoutedCommand MyCommand = new RoutedCommand();
    ....
}

and in my MainWindow.xaml, I am hooking this command with my implementations in MainWindow.xaml.cs as:

<CommandBinding Command="{x:Static Designer:DesignerCanvas.MyCommand}"
                    Executed="DoStuff"
                    CanExecute="CanDoStuff" /> 

And in my ResourceDictionary.xaml, I am having a Button that I am hooking the ContextMenu with using Triggers:

    <Button x:Name="btnMyButton" Content="Click this">
      <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>
          <Setter Property="ContextMenu">
            <Setter.Value>
              <ContextMenu>
                <MenuItem x:Name="myMenu" Header="MyMenuItem 1">
                  <MenuItem x:Name="menuItem1" Header="MySubMenuItem 1"
Command="{x:Static DesignerItems:DesignerCanvas.MyCommand}">     <<<=== Command Binding
                    <MenuItem.Icon>
                      <Image Source="myImage.png" Width="20"/>
                    </MenuItem.Icon>
                  </MenuItem>
                </MenuItem>
              </ContextMenu>
            </Setter.Value>
          </Setter>
        </Style>
      </Button.Style>
    </Button>

But this doesn't seem to be working since the menu item that has a Command specified in the XAML is being shown as disabled and also neither of the CanDoStuff() and DoStuff() are getting hit by the debugger. Also, since i am NOT using a ViewModel for this, I am UNABLE TO write something like:

<MenuItem Command="{Binding Path=somePathInViewModel, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=Button}}" />

How can I do this, any help would be greatly appreciated. Thanks in advance.

¿Fue útil?

Solución 2

Finally got it working, was doing some silly mistakes!

Had to change the static command initialization to have ContextMenu as its owner

public static RoutedCommand MyCommand = new RoutedCommand("MyCommand", typeof(ContextMenu));

in MainWindow.xaml.cs, added a method to register command binding and called it from MainWindow's contructor:

private void InitializeMenuItemsCommands()
    {
        CommandManager.RegisterClassCommandBinding(typeof(ContextMenu), new CommandBinding(DesignerCanvas.TestDialog, OpenTestDialog, CanOpenTestDialog));
    }

And finally the handlers for CanExecute and Executed events:

private void CanOpenTestDialog(object sender, CanExecuteRoutedEventArgs e)
{
    e.CanExecute = true; // set if MenuItem is enabled
}

private void OpenTestDialog(object sender, ExecutedRoutedEventArgs e)
{
    // handle the MenuItem click here
}

DIDN'T have to change anything in my ResourceDictionary for MenuItem, so here is the MenuItem again :

<MenuItem x:Name="menuItem1" Header="MySubMenuItem 1"
Command="{x:Static DesignerItems:DesignerCanvas.MyCommand}">     <<<=== Command Binding
                <MenuItem.Icon>
                  <Image Source="myImage.png" Width="20"/>
                </MenuItem.Icon>
              </MenuItem>

Otros consejos

You are actually doing everything fine in your code but there are few hidden bugs/features about ContextMenus in WPF. Those bad boys lack on WPF's usual functionalities. ContextMenu is actually just a dump property available for each control in WPF which injects its list of items into VisualTree once user fires right click.

To solve your issue do not set ContextMenu in Style and do not set CommandBinding on Window level but instead set it on ContextMenu's level.

Though most important is to have ContextMenu NOT set in Style!

Edit:

Place your ContextMenu away from Style and set your CommandBinding like this:

<ContextMenu>
    <ContextMenu.CommandBindings>
        <CommandBinding Command="foo:MyCommands.CmdFoo" 
                        CanExecute="CanExecuteRerollCommand" 
                        Executed="ExecuteRerollCommand" />
    </ContextMenu.CommandBindings>
    <MenuItem Header="Reroll"  Command="foo:MyCommands.CmdFoo"/>
</ContextMenu>
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top