按钮上的ContextMenu单击不触发命令

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)

我可以确认我的视图模型没有任何问题,因为当我右键单击按钮然后单击上下文菜单时命令会触发.

Roh*_*ats 7

PlacementTargetnull您手动设置ContextMenu.IsOpen属性时,因为只有在通过右键单击目标控件打开它后才将其设置为实际值.(PopUpService类负责将此值设置为实际目标).

由于PlacementTargetnull在当你通过打开的情况下Storyboard,结合是不能够解决实际命令它绑定到.

所以,问题是你需要在传递DataContextButtonMenuItem,这样的结合可以得到解决.(MenuItem与按钮的视觉树不同).这可以通过两种方式实现:


使用x:Reference(在WPF提供4.0及更高版本),但你需要声明伪控制,以便它可以被引用来获得DataContextVisibility设置为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)