Why is this WPF RoutedCommand related to Context MenuItem disabled?

I am still around WPF at the moment and cannot understand why this context menu item is disabled:

<Window x:Class="DisabledMenuItemProblem.Window1" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="clr-namespace:DisabledMenuItemProblem" Title="Window1" Height="300" Width="300"> <TextBlock Text="fooooobaaaaaar"> <TextBlock.ContextMenu> <ContextMenu> <MenuItem Header="Foo" Command="{x:Static local:MyCommands.FooBar}" /> </ContextMenu> </TextBlock.ContextMenu> </TextBlock> </Window> using System.Windows; using System.Windows.Input; namespace DisabledMenuItemProblem { public partial class Window1 : Window { public Window1() { InitializeComponent(); CommandBindings.Add(new CommandBinding(MyCommands.FooBar, FooExecuted, CanFooExecute)); } public void FooExecuted(object sender, ExecutedRoutedEventArgs e) { MessageBox.Show("Foo!"); } public void CanFooExecute(object sender, CanExecuteRoutedEventArgs e) { e.CanExecute = true; } } public static class MyCommands { public static RoutedCommand FooBar = new RoutedCommand(); } } 

What am I missing?

What also puzzles me is that if I close the button in the window and put its command in FooBar, it will work, and after its execution the context menu will be turned on!

Hi guys, Chris.

+6
wpf menuitem
source share
5 answers

here is the generic template i use ....

first save your commands in your static class, this encourages reuse, etc.

 public static class MyCommands { public static RoutedUICommand CmdFoo = new RoutedUICommand("CmdFoo", "CmdFoo", typeof(MyCommands)); } 

second, register the command in the control / window / etc. you want to use it, as a rule, in the constructor

 public MyControl { public MyControl() { CommandBindings.Add( new CommandBinding( MyCommands.CmdFoo, // this is the command object XCutFooCommand, // execute CanXCuteFooCommand));// can execute? } 

third, create handlers in the control / window / etc .....

  public void CanExecuteRerollCommand(object sender, CanExecuteRoutedEventArgs e) { e.CanExecute = true; // can this command be executed? e.Handled = true; // has this event been handled? } public void ExecuteRerollCommand(object sender, ExecutedRoutedEventArgs e) { // do stuff } } 

Finally, your xaml should look like this:

  <ContextMenu> <ContextMenu.CommandBindings> <CommandBinding Command="foo:MyCommands.CmdFoo" CanExecute="CanExecuteRerollCommand" Executed="ExecuteRerollCommand" /> </ContextMenu.CommandBindings> <MenuItem Header="Reroll" Command="foo:MyCommands.CmdFoo"/> </ContextMenu> 

note the lack of binding. Also note the <CommandBinding> in <ContextMenu> . here is the link .... http://www.wiredprairie.us/journal/2007/04/commandtarget_menuitem_context.html

disabled command is addressed to this site

+10
source share

For those who are looking for the answer to this question - after trawling on the Internet, I found the most effective answer to include the following in any MenuItem announcement for which its commands should be heard by the "owner".

In the conditions of a layman; if you want the commands of your context menu to be heard by right-clicking. 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 in templates (something I found many other solutions that are not supported). Here is an explanation of the meaning of the statement taken from other sources (I am terribly explaining things):

Each FrameworkElement element has a DataContext, which is an arbitrary object. By default, the data binding source is a DataContext. You can use RelativeSource.Self to change the binding source to the FrameworkElement itself, and not to the DataContext. Thus, the RelativeSource part simply moves you โ€œone levelโ€ from the DataContext of the FrameworkElement to the FrameworkElement itself. When you are in FrameworkElement, you can specify the path to any of its properties. If the FrameworkElement is a popup, it will have a PlacementTarget property, which is another FrameworkElement that pops up relative to.

In short, if you have a Popup positioned relative to a TextBox, for example, this expression sets the DataContext of the popup to the TextBox, and as a result {Binding Text} somewhere in the body of the Popup will bind to the text of the text field.

I sincerely hope that this information will save those who are new to WPF, the headache that I experienced this weekend ... although it taught me a lot!

Steve

+8
source share

As far as I understand, this is what happens. When ContextMenu is displayed, it is displayed in a popup window, which is basically a separate window. Popup does not belong to the same visual tree as the main contents of your window, and therefore the command does not โ€œbubbleโ€ into your main window. This is why your CanExecute method is never called. If, for example, you attach CommandBindings to ContextMenu itself, CanExecute will be called correctly.

However, I really remember reading somewhere that Popup in some cases should not behave like a normal window, and some things should โ€œbubbleโ€.

I think there must be some kind of inner magic. If you just change TextBlock to TextBox, then it seems to work. I am sure that Reflector will show you additional logic in TextEditorBase or something like that.

If you really need to use TextBlock, I will probably manually add CommandBinding to ContextMenu itself, and not to the window.

+2
source share

An even simpler answer would be to add a Focus () call in the Window constructor. Yesterday I came across this issue and spent a lot of time figuring out what was going on. I wrote about this here: http://cebla5.spaces.live.com/blog/cns!1B8262ED00250003!206.entry

A blog post will explain why the Focus () call works in the constructor.

0
source share

I found the easiest way to overcome this problem: move the context menu to the window resource and point it there

 <ContextMenu x:Key="ControlContextMenu"> <ContextMenu.CommandBindings> <CommandBinding Command="{StaticResource CloseCommand}" Executed="CloseExecuted" CanExecute="CloseCanExecute" /> </ContextMenu.CommandBindings> <MenuItem Command="{StaticResource CloseCommand}" /> </ContextMenu> 

and then on UIElement just set the ContextMenu property

 <TextBlock ContextMenu="{StaticResource ControlContextMenu}"/> 
0
source share

All Articles