Catel - CommandManager未传递CommandParameter

时间:2017-03-15 13:40:43

标签: c# wpf mvvm catel

我有一个带有" MainView"的Catel应用程序。和一些嵌套的视图。 嵌套视图的ListView包含一些ContextMenuMenuItems的项目。

在MainView的ViewModel中,我创建了一个TaskCommand<object>,它将对传递的参数执行某些操作。此传递的参数应该是SelectedItem的当前ListView。此命令正在全球注册到ICommandManager

如果我使用MenuItem中带有绑定命令的ICommandManager点击,则传递的参数将始终为null

这里有相关代码:

NestedView.xaml

<catel:UserControl
  x:Name="UserControl"
  x:Class="My.NameSpace.Views.View"
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  xmlns:catel="http://catel.codeplex.com">

...
  <ListView ItemsSource="{Binding Items}"
            BorderThickness="0"
            SelectedItem="{Binding SelectedItem}"
            HorizontalContentAlignment="Stretch">
    <ItemsControl.ItemTemplate>
      <DataTemplate>
        <TextBlock VerticalAlignment="Center"
                   Margin="2.5"
                   Text="{Binding Description}">
          <TextBlock.ContextMenu>
            <ContextMenu>
              <MenuItem Header="Do Stuff"
                        Command="{catel:CommandManagerBinding DoStuffCommand}"
                        CommandParameter="{Binding DataContext.SelectedItem, ElementName=UserControl}" />
              ...
            </ContextMenu>
          </TextBlock.ContextMenu>
        </TextBlock>
      </DataTemplate>
    </ItemsControl.ItemTemplate>
  </ListView>
...
</catel:UserControl>

MainViewModel.cs

public class MainViewModel : ViewModelBase {
    ...

    public ICommand DoStuffCommand { get; }

    public MainViewModel(ICommandManager commandManager, IUIVisualizerService uiVisualizerService, IMessageService messageService)
    {
      ...

      DoStuffCommand = new TaskCommand<object>(OnDoStuffCommandExecute);

      commandManager.CreateCommand(nameof(DoStuffCommand));
      commandManager.RegisterCommand(nameof(DoStuffCommand), DoStuffCommand, this);
    }

    private async Task OnDoStuffCommandExecute(object parameter)
    {
      // command needs to be in the MainViewModel because there will be some modification on the MainView based on parameter (adding tabs, etc)
      Debugger.Break();
    }

    ...
}

如果您需要更多代码,我也可以发布此代码,但这应该足够了。

我还看了一下Catel的CommandManager实现,发现了这个:

    /// <summary>
    /// Executes the command.
    /// </summary>
    /// <param name="commandName">Name of the command.</param>
    /// <exception cref="ArgumentException">The <paramref name="commandName"/> is <c>null</c> or whitespace.</exception>
    /// <exception cref="InvalidOperationException">The specified command is not created using the <see cref="CreateCommand"/> method.</exception>
    public void ExecuteCommand(string commandName)
    {
        Argument.IsNotNullOrWhitespace("commandName", commandName);

        lock (_lockObject)
        {
            Log.Debug("Executing command '{0}'", commandName);

            if (!_commands.ContainsKey(commandName))
            {
                throw Log.ErrorAndCreateException<InvalidOperationException>("Command '{0}' is not yet created using the CreateCommand method", commandName);
            }

            _commands[commandName].Execute(null);
        }
    }

我假设如果单击MenuItem将会调用此方法并解释行为。

是否有适当的解决方案/解决方法将(绑定)参数传递给我的OnExecute方法?

提前致谢

2 个答案:

答案 0 :(得分:1)

  1. 在xaml中命令绑定之前设置CommandParameter绑定

    MenuItem Header =“Do Stuff”     CommandParameter =“{Binding DataContext.SelectedItem,ElementName = UserControl}”     Command =“{catel:CommandManagerBinding DoStuffCommand}”

  2. 请注意,菜单项中的绑定上下文是,而不是视图模型。如果要绑定到视图模型,则需要为根网格提供一个名称,并按以下方式绑定:

    CommandParameter="{Binding DataContext.SelectedItem, ElementName=rootGrid}"
    
  3. 请注意,使用UserControl无法正常工作,因为VM已设置在内部网格中(有关解释原因,请参阅文档)。因此,请使用UserControl.ViewModelSomeInnerControl.DataContext

答案 1 :(得分:1)

好的,我找到了解决方案,但实际上有点奇怪。

首先交换Command={...}CommandParamter={...}的顺序(如Geert所说)。 然后经过很多失败后我才开始工作:只需进入CommandParameter - 绑定标记而不是其他任何东西。所以MenuItem的我的XAML代码如下所示:

  <MenuItem Header="Do Stuff"
            CommandParameter="{Binding}"
            Command="{catel:CommandManagerBinding DoStuffCommand}"/>

编辑:

好的,现在我得到了一个解决方案(我认为)。上面的方法大部分时间都有效,但可能会遇到问题,因为@ mm8指出。

所以我用Google搜索了更多内容并发现:https://stackoverflow.com/a/3668699(请参阅更新2)

在这个给出的答案解决方案现在对我来说很好,因为我可以直接绑定到我的ViewModel并通过绑定获得所需的值。