问题描述
这是一个问题.
我在单击按钮时显示上下文菜单,并且菜单命令绑定到视图模型中的 ICommand
.菜单显示在按钮单击和右键单击上.问题是当我单击按钮然后单击上下文菜单时菜单单击没有触发,但是当我右键单击按钮然后单击菜单时我可以确认菜单正在工作.
I am displaying context menu on a button click and the menu command is bind to ICommand
in the view model. Menu is displaying on the button click as well as on the right click. The problem is menu click is not firing when I click button and then click context menu, but I can confirm that menu is working when I right click on button and then click on menu.
<Button Grid.Row="3" Width="500" Height="30" Name="cmButton" >
Button with Context Menu
<Button.ContextMenu>
<ContextMenu DataContext="{Binding Path=PlacementTarget.DataContext, RelativeSource={RelativeSource Mode=Self}}" >
<MenuItem DataContext="{Binding}" Header="New Layout Element..." Command="{Binding Path=SubmitBtn}" />
</ContextMenu>
</Button.ContextMenu>
<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>
</Style>
</Button.Style>
</Button>
我可以确认我的视图模型没有任何问题,因为当我右键单击按钮然后单击上下文菜单时会触发命令.
I can confirm there is nothing wrong in my view model because command is firing when I do right click on button then click on context menu.
推荐答案
PlacementTarget
在你手动设置 ContextMenu.IsOpen
属性时是 null
因为只有在通过右键单击目标控件打开它时才将其设置为实际值.(PopUpService
类负责将此值设置为实际目标).
PlacementTarget
is null
when you manually set ContextMenu.IsOpen
property because it is set to actual value only once it's open by right clicking on target control. (PopUpService
class is responsible for setting this value to actual target).
由于 PlacementTarget
为 null
以防当您通过 Storyboard
打开它时,绑定无法解析它所绑定的实际命令到.
Since PlacementTarget
is null
in case when you open it via Storyboard
, binding is not able to resolve actual command it's binded to.
所以,问题是您需要将 Button
的 DataContext
传递给 MenuItem
以便解决绑定问题.(MenuItem
与按钮的视觉树不同).这可以通过两种方式实现:
So, issue is you need to pass on the DataContext
of Button
to the MenuItem
so that binding can be resolved. (MenuItem
are not is same visual tree as that of button). That can be achieved via two ways:
使用 x:Reference
(在 WPF 4.0 及更高版本中可用)但您需要声明虚拟控件以便可以引用它来获取 DataContext将
Visibility
设置为 Collapsed
的 code>.
Using x:Reference
(available in WPF 4.0 and higher) but you need to declare dummy control so that it can be referenced to get DataContext
with Visibility
set to Collapsed
.
<FrameworkElement x:Name="dummyControl" Visibility="Collapsed"/>
<Button Width="100" Height="30" Name="cmButton">
<Button.ContextMenu>
<ContextMenu>
<MenuItem Header="New Layout Element..."
Command="{Binding Path=DataContext.SubmitBtn,
Source={x:Reference dummyControl}}" />
</ContextMenu>
</Button.ContextMenu>
</Button>
另一个有趣的事情是 Freezable
对象继承 DataContext
即使它们不位于 VisualTree
所以我们可以使用这个特性来克服我们需要继承DataContext
的情况.
Another interesting thing is Freezable
objects inherit DataContext
even if they don't lie in VisualTree
so we can use this feature to overcome situations where we need to inherit DataContext
.
首先我们需要创建继承自 Freezable 的类
并公开可以绑定的 DP:
First we need to create class inheriting from Freezable
and exposing DP which can be bind to:
public class BindingProxy : Freezable
{
#region Overrides of Freezable
protected override Freezable CreateInstanceCore()
{
return new BindingProxy();
}
#endregion
public object Data
{
get { return (object)GetValue(DataProperty); }
set { SetValue(DataProperty, value); }
}
public static readonly DependencyProperty DataProperty =
DependencyProperty.Register("Data", typeof(object), typeof(BindingProxy));
}
现在我们可以像这样在 XAML 中使用它:
Now we can use it in XAML like this:
<Button Width="100" Height="30" Name="cmButton">
<Button.Resources>
<local:BindingProxy x:Key="proxy" Data="{Binding}"/>
</Button.Resources>
<Button.ContextMenu>
<ContextMenu>
<MenuItem Header="New Layout Element..."
Command="{Binding Path=Data.SubmitBtn,
Source={StaticResource proxy}}" />
</ContextMenu>
</Button.ContextMenu>
</Button>
这篇关于按钮单击时的 ContextMenu 未触发命令的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!