本文介绍了按钮单击时的 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 在你手动设置 ContextMenu.IsOpen 属性时是 null 因为只有在通过右键单击目标控件打开它时才将其设置为实际值.(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 的 code>.

Using x:Reference (available in WPF 4.0 and higher) but you need to declare dummy control so that it can be referenced to get DataContext with Visibility set to 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 未触发命令的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

07-29 16:35