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

时间:2014-01-25 20:10:49

标签: wpf button onclick contextmenu

这是一个问题。

我在点击按钮时显示上下文菜单,菜单命令绑定到视图模型中的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>

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

2 个答案:

答案 0 :(得分:7)

当您手动设置PlacementTarget属性时,

nullContextMenu.IsOpen,因为只有在通过右键单击目标控件打开后才将其设置为实际值。 (PopUpService类负责将此值设置为实际目标。)

由于PlacementTargetnull,如果您通过Storyboard打开它,绑定无法解析绑定到的实际命令。

因此,问题是您需要将DataContext的{​​{1}}传递给Button,以便解析绑定。 (MenuItem与按钮的视觉树不同。这可以通过两种方式实现:


使用 MenuItem (在WPF 4.0及更高版本中提供),但您需要声明虚拟控件,以便可以引用它以x:Reference获取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

现在我们可以像这样在XAML中使用它:

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));
}

答案 1 :(得分:1)

之所以发生这种情况是因为DataContext的{​​{1}}是ContextMenu,您只需要在null点击事件时设置他。看看样本:

XAML:

Button

背后的代码

<Button Content="More..." Click="ButtonMoreClick" ContextMenu="{StaticResource ContextMenu1}"/>

我希望帮助