【问题标题】:ContextMenu on button click not firing command按钮单击时的 ContextMenu 未触发命令
【发布时间】:2014-02-16 19:18:45
【问题描述】:

这是一个问题。

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

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

【问题讨论】:

    标签: wpf button onclick contextmenu


    【解决方案1】:

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

    由于PlacementTargetnull,当你通过Storyboard打开它时,绑定无法解析它所绑定的实际命令。

    所以,问题是您需要将ButtonDataContext 传递给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>
    

    另一个有趣的事情是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));
    }
    

    现在我们可以像这样在 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>
    

    【讨论】:

    • Rohit,我尝试了第二种方法,效果很好。非常感谢您,以后联系您。
    • 当然。很高兴帮助贾斯汀.. :)
    【解决方案2】:

    这是因为ContextMenuDataContextnull,您只需将他设置为来自Button 的事件点击。查看示例:

    XAML:

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

    隐藏代码

    private void ButtonMoreClick(object sender, RoutedEventArgs e)
    {
        var menu = (sender as Button).ContextMenu;
        menu.DataContext = DataContext;
        menu.IsOpen = true;
    }
    

    希望能帮到你

    【讨论】:

      猜你喜欢
      • 2012-01-15
      • 1970-01-01
      • 2011-09-30
      • 1970-01-01
      • 1970-01-01
      • 2020-03-26
      • 2012-03-14
      • 2014-01-17
      • 1970-01-01
      相关资源
      最近更新 更多