【问题标题】:WPF MenuItem Command.Executed not firing, but Command.CanExecute doesWPF MenuItem Command.Executed 未触发,但 Command.CanExecute 触发
【发布时间】:2014-03-07 16:31:46
【问题描述】:

这几天让我发疯了!

我无法让命令的“已执行”部分在菜单“1 级”以下的任何内容上触发。我可以看到始终在所有菜单项上调用“CanExecute”回调,并且回调始终返回 true。

请有人指出我正确的方向吗?我知道我可以在 MyTypes:MyMenuDescriptorType 中添加 ICommand 的实现,但这不适合我想要实现的模型。

在此先感谢

private void CreateActionCommand_CanExecute(object sender, CanExecuteRoutedEventArgs e)
{
    e.CanExecute = true;
    e.Handled = true;
}
private void CreateActionCommand_Executed(object sender, ExecutedRoutedEventArgs e)
{
    Debug.WriteLine("This only happens on Level 1");
}

<UserControl.Resources>
    <ResourceDictionary>
        <RoutedUICommand x:Key="CreateAction" Text="CreateAction"/>
    </ResourceDictionary>
</UserControl.Resources>    
<Grid x:Name="LayoutRoot">
    <Menu>
        <Menu.CommandBindings>
            <CommandBinding Command="{StaticResource CreateAction}" Executed="CreateActionCommand_Executed" CanExecute="CreateActionCommand_CanExecute"/>               
        </Menu.CommandBindings>         
        <Menu.Resources>
            <Style x:Key="MyMenuStyle" TargetType="{x:Type MenuItem}">
                <Setter Property="Header" Value="{Binding Description}"/>
                <Setter Property="Command" Value="{StaticResource CreateAction}" />
                <Setter Property="CommandParameter" Value="{Binding}"/>
                <Setter Property="CommandTarget" Value="{Binding Path=., RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Menu}}}"/>                   
            </Style>                                        
        </Menu.Resources>           
        <MenuItem Header="Root Level">
            <MenuItem Header="Level 1" ItemsSource="{Binding MyListOfThings}" ItemContainerStyle="{StaticResource MyMenuStyle}">
                <MenuItem.Resources>
                    <HierarchicalDataTemplate 
                        DataType="{x:Type MyTypes:MyMenuDescriptorType}" 
                        ItemsSource="{Binding Path=Children}" 
                        ItemContainerStyle="{StaticResource MyMenuStyle}"/>
                </MenuItem.Resources>
            </MenuItem>
        </MenuItem>
    </Menu>
</Grid>

更新:我已经弄清楚出了什么问题。我的简化示例没有更新属性“MyListOfThings”。如果我在菜单的 PreviewMouseLeftButtonDown 事件中更新“MyListOfThings”,则控件会执行奇怪的操作并且命令不会触发。但是,如果我在 MouseOver 事件中更新属性,那么一切都会按预期工作!

我不确定这是为什么。也许有人可以解释一下?

【问题讨论】:

    标签: c# wpf hierarchicaldatatemplate commandbinding


    【解决方案1】:

    你可以尝试实现一个DelegateCommand,你可以找到snippet code here

    在您的 MenuItem 之后,将如下所示:

    <MenuItem Header="DoSomething" Command="{Binding DoSomethingCommand}"/>
    

    在您的 ViewModel 中:

    public MainViewModel()
        {
            DoSomethingCommand= new DelegateCommand(DoSomethingCommandExec, DoSomethingCommandCanExec);
        }
    
        public ICommand DoSomethingCommand{ get; private set; }
    
        private bool DoSomethingCommandCanExec()
        {
            return true;
        }
    
        private void DoSomethingCommandExec()
        {
            // DoSomethingCommand
        }
    

    我认为这是实现它的好方法。每个 MenuItem 都会有一个命令。您可以将 Menuitems 放入可以绑定到与此处相同的命令的 MenuItem 中。

    喜欢:

    <MenuItem Header="DoSomething" Command="{Binding DoSomethingCommand}">
        <MenuItem Header="DoSomething" Command="{Binding DoSomethingCommand}"/>
    </MenuItem>
    

    希望有所帮助。

    您好!

    【讨论】:

      【解决方案2】:

      基于this 问题。它对我有用:

      哈姆:

      <Window x:Class="WpfApplication3.MainWindow"
          xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
          xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
          xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
          xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
          xmlns:local="clr-namespace:WpfApplication3"
          mc:Ignorable="d"
          Title="MainWindow" Height="350" Width="525">
      <Window.Resources>
          <ResourceDictionary>
              <ContextMenu x:Key="ContextMenu1">
                  <MenuItem Header="Menu1" Command="{Binding PlacementTarget.Tag.Menu1Executed, RelativeSource={RelativeSource AncestorType=ContextMenu}}" />
              </ContextMenu>
          </ResourceDictionary>
      </Window.Resources>
      
      <Grid ShowGridLines="True" ContextMenu="{DynamicResource ContextMenu1}" Tag="{Binding}">
          <Grid.RowDefinitions>
              <RowDefinition Height="100*"/>
          </Grid.RowDefinitions>
      
          <Grid.ColumnDefinitions>
              <ColumnDefinition Width="100*"/>
          </Grid.ColumnDefinitions>
      
          <Label Grid.Column="1" Content="Content" Margin="2"/>
      </Grid>
      

      cs:

      public partial class MainWindow : Window
      {
          public MainWindow()
          {
              InitializeComponent();
              DataContext = new MainWindowViewModel();
          }
      }
      
      public class MainWindowViewModel
      {
          public MainWindowViewModel()
          {
              Menu1Executed = new DelegateCommand(ShowMenu1);
          }
      
          public ICommand Menu1Executed { get; set; }
      
          private void ShowMenu1(object obj)
          {
              // Yay!
          }
      }
      
      public class DelegateCommand : ICommand
      {
          private readonly Action<object> execute;
          private readonly Predicate<object> canExecute;
      
          public DelegateCommand(Action<object> execute)
              : this(execute, null)
          { }
      
          public DelegateCommand(Action<object> execute, Predicate<object> canExecute)
          {
              if (execute == null)
                  throw new ArgumentNullException("execute");
      
              this.execute = execute;
              this.canExecute = canExecute;
          }
      
          #region ICommand Members
      
          [DebuggerStepThrough]
          public bool CanExecute(object parameter)
          {
              return canExecute == null ? true : canExecute(parameter);
          }
      
          public event EventHandler CanExecuteChanged
          {
              add { CommandManager.RequerySuggested += value; }
              remove { CommandManager.RequerySuggested -= value; }
          }
      
          public void Execute(object parameter)
          {
              execute(parameter);
          }
      
          #endregion
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2010-09-24
        • 1970-01-01
        • 2019-04-05
        相关资源
        最近更新 更多