Jus*_*hew 2 wpf contextmenu onclick button
这是一个问题.
我在按钮单击时显示上下文菜单,菜单命令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>
Run Code Online (Sandbox Code Playgroud)
我可以确认我的视图模型没有任何问题,因为当我右键单击按钮然后单击上下文菜单时命令会触发.
PlacementTarget
是null
您手动设置ContextMenu.IsOpen
属性时,因为只有在通过右键单击目标控件打开它后才将其设置为实际值.(PopUpService
类负责将此值设置为实际目标).
由于PlacementTarget
是null
在当你通过打开的情况下Storyboard
,结合是不能够解决实际命令它绑定到.
所以,问题是你需要在传递DataContext
的Button
到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>
Run Code Online (Sandbox Code Playgroud)
另一个有趣的事情是Freezable
对象继承,DataContext
即使它们不存在,VisualTree
所以我们可以使用此功能来克服我们需要继承的情况DataContext
.
首先,我们需要create class inheriting from Freezable
并暴露可以绑定到的DP:
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));
}
Run Code Online (Sandbox Code Playgroud)
现在我们可以像这样在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>
Run Code Online (Sandbox Code Playgroud)