Reputation: 2750
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.
Upvotes: 3
Views: 2678
Reputation: 2750
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>
Upvotes: 4
Reputation: 8791
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>
Upvotes: 3