为什么此 WPF RoutedCommand 绑定上下文菜单项被禁用?
我目前仍在摸索 WPF,并且无法弄清楚为什么此上下文菜单项被禁用:
<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();
}
}
我缺少什么?
同样让我困惑的是,如果我在窗口中扔一个按钮并将其命令设置为 FooBar,它就会起作用,并且一旦执行,上下文菜单就会启用!
干杯,伙计们, 克里斯。
I'm still fumbling my way around WPF at the moment, and can not figure out 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>
Code Behind:
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's also baffling me is that if i throw a button in the window and set its command to FooBar it works, and once its been executed, then the context menu gets enabled!
Cheers guys,
Chris.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
这是我使用的一般模式....
首先,将命令保存在自己的静态类中,这可以促进重用等....
其次,在控件/窗口/等中注册命令。 你想使用它,通常是在构造函数中
,在控件/窗口/等中创建处理程序......
最后,你的 xaml 应该如下所示:
注意没有绑定。 另外,请注意
中的
。这是一个参考......
http://www.wiredprairie.us/journal/2007/04/commandtarget_menuitem_context.html
被禁用的命令位于此站点
here is the general pattern that I use....
first, keep your commands in thier own static class, this promotes reuse,etc....
second, register the command in the control/window/etc. you want to use it in, normally in the constructor
third, create your handlers in the control/window/etc.....
lastly, your xaml ought to look like this:
notice that there is no binding. Also, notice the
<CommandBinding>
in the<ContextMenu>
.here is a reference....
http://www.wiredprairie.us/journal/2007/04/commandtarget_menuitem_context.html
the command being disabled is addressed at this site
对于任何寻找此问题答案的人 - 在搜索互联网后,我发现最有效的答案是在需要其“所有者”听到其命令的 MenuItem 的任何声明中包含以下内容。
通俗地说; 如果您希望右键单击的内容能够听到上下文菜单的命令。 添加此代码:
CommandTarget =“{Binding Path = PlacementTarget,RelativeSource = {RelativeSource AncestorType = ContextMenu}}”
示例:
这也适用于模板(我发现很多其他解决方案不支持)。 以下是从其他地方摘取的对该声明含义的解释(我对解释事情感到震惊):
老实说,我希望这些信息可以帮助刚接触 WPF 的人解决我这个周末所经历的头痛……尽管它确实教会了我很多东西!
史蒂夫
For anyone 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:
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):
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!
Steve
据我了解,这就是发生的事情。
当显示 ContextMenu 时,它会显示在弹出窗口中,该弹出窗口基本上是一个单独的窗口。 弹出窗口与窗口中的主要内容不属于同一视觉树,因此命令不会“冒泡”到主窗口中。 这就是为什么您的 CanExecute 方法永远不会被调用的原因。 例如,如果您将 CommandBindings 附加到 ContextMenu 本身,则 CanExecute 将被正确调用。
不过,我确实记得在某处读过,在某些情况下,弹出窗口不应表现得像普通窗口,某些东西应该“冒泡”。
我想一定有某种内在的魔力正在发生。 例如,如果您只是将 TextBlock 更改为 TextBox,那么它似乎可以工作。 我打赌 Reflector 会向您展示 TextEditorBase 中的一些额外逻辑或类似的东西。
如果您确实需要使用 TextBlock,我可能会手动将 CommandBinding 添加到 ContextMenu 本身而不是窗口上。
As far as I understand this is what happens.
When the ContextMenu is shown it is shown in a Popup which is basically a separate Window. The Popup does not belong to the same visual tree as the main content in your Window and therefore the Command doesn't 'bubble' up into your main window. This is why your CanExecute method is never called. If for example you attach the CommandBindings on the ContextMenu itself the CanExecute will be called correctly.
However I do recall reading somewhere that the Popup in certain cases should not behave like an ordinary Window and certain things should 'bubble' up.
I think there must be some internal magic going on. If you simply change the TextBlock to a TextBox for example it seems to work. I bet Reflector would show you some extra logic in the TextEditorBase or something like that.
If you really need to use a TextBlock I probably would manually add the CommandBinding to the ContextMenu itself rather than on the window.
我发现解决这个问题的最简单方法是将上下文菜单移动到窗口资源中并从那里引用它
,然后在 UIElement 上设置 ContextMenu 属性
I have found the easiest way to overcome this issue is move the context menu into a window resource and reference it from there
and then on the UIElement just set the ContextMenu property
一个更简单的答案是在 Window 的构造函数中添加对 Focus() 的调用。 我昨天遇到了这个问题,花了相当多的时间弄清楚发生了什么。 我在这里写了博客:http://cebla5.spaces.live。 com/blog/cns!1B8262ED00250003!206.entry
这篇博文将解释为什么在构造函数中调用 Focus() 会起作用。
An even simpler answer would be to add a call to Focus() in the Window's constructor. I bumped into this issue yesterday and spent quite a bit of time figuring out what was going on. I blogged about it here: http://cebla5.spaces.live.com/blog/cns!1B8262ED00250003!206.entry
The blog post will explain why calling Focus() in the constructor works.