提问人:Justin Mathew 提问时间:1/26/2014 最后编辑:Vadim OvchinnikovJustin Mathew 更新时间:5/25/2017 访问量:3705
ContextMenu 在按钮单击时不触发命令
ContextMenu on button click not firing command
问:
这是一个问题。
我在单击按钮时显示上下文菜单,并且菜单命令绑定到视图模型中。菜单显示在按钮单击和右键单击时。问题是当我单击按钮然后单击上下文菜单时,菜单单击没有触发,但是当我右键单击按钮然后单击菜单时,我可以确认菜单正在工作。ICommand
<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>
我可以确认我的视图模型没有问题,因为当我右键单击按钮然后单击上下文菜单时,命令正在触发。
答:
PlacementTarget
是当您手动设置属性时,因为只有在右键单击目标控件打开它时,它才会设置为实际值。(类负责将此值设置为实际目标)。null
ContextMenu.IsOpen
PopUpService
由于 PlacementTarget
在通过 Storyboard
打开它时为 null
,因此绑定无法解析它绑定到的实际命令。
因此,问题是您需要将 Button
的 DataContext
传递给 MenuItem
,以便可以解析绑定。(与按钮的可视化树不同)。这可以通过两种方式实现:MenuItem
使用 x:Reference
(在 WPF 4.0 及更高版本中可用),但您需要声明虚拟控件,以便可以引用它以获取 设置为 .DataContext
Visibility
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
首先,我们需要公开 DP,它可以绑定到:create class inheriting from Freezable
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 中使用它,如下所示:
<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>
评论
之所以发生这种情况,是因为 是 ,你只需要在事件点击时设置他。查看示例:DataContext
ContextMenu
null
Button
XAML:
<Button Content="More..." Click="ButtonMoreClick" ContextMenu="{StaticResource ContextMenu1}"/>
代码背后
private void ButtonMoreClick(object sender, RoutedEventArgs e)
{
var menu = (sender as Button).ContextMenu;
menu.DataContext = DataContext;
menu.IsOpen = true;
}
我希望能帮到你
评论