按钮单击时的 ContextMenu 不触发命令 [英] ContextMenu on button click not firing command

查看:31
本文介绍了按钮单击时的 ContextMenu 不触发命令的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这里有一个问题.

我在单击按钮时显示上下文菜单,菜单命令绑定到视图模型中的 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 is null 当您手动设置 ContextMenu.IsOpen 属性时,因为只有在通过右键单击目标控件打开后才将其设置为实际值.(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).

由于 PlacementTargetnull,如果您通过 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.

因此,问题是您需要将 ButtonDataContext 传递给 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 及更高版本中可用)但您需要声明虚拟控件,以便可以引用它以获取 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>

<小时>

另一个有趣的事情是 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 不触发命令的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆