【问题标题】:Passing a parameter using RelayCommand defined in the ViewModel (from Josh Smith example)使用 ViewModel 中定义的 RelayCommand 传递参数(来自 Josh Smith 示例)
【发布时间】:2010-10-23 01:14:29
【问题描述】:

我想通过使用 RelayCommand 将我的应用程序的 XAML(视图)中定义的参数传递给 ViewModel 类。我关注了Josh Smith's excellent article on MVVM,并实现了以下内容。

XAML 代码

        <Button 
        Command="{Binding Path=ACommandWithAParameter}"
        CommandParameter="Orange"
        HorizontalAlignment="Left" 
        Style="{DynamicResource SimpleButton}" 
        VerticalAlignment="Top" 
        Content="Button"/>

ViewModel 代码

  public RelayCommand _aCommandWithAParameter;
  /// <summary>
  /// Returns a command with a parameter
  /// </summary>
  public RelayCommand ACommandWithAParameter
  {
     get
     {
        if (_aCommandWithAParameter == null)
        {
           _aCommandWithAParameter = new RelayCommand(
               param => this.CommandWithAParameter("Apple")
               );
        }

        return _aCommandWithAParameter;
     }
  }

  public void CommandWithAParameter(String aParameter)
  {
     String theParameter = aParameter;
  }
  #endregion

我在 CommandWithAParameter 方法中设置了一个断点,并观察到 ​​aParameter 设置为“Apple”,而不是“Orange”。这似乎很明显,因为使用文字字符串“Apple”调用了 CommandWithAParameter 方法。

但是,查看执行堆栈,我可以看到“橙色”,我在XAML中设置的CommandParameter是ICommand Execute接口方法的RelayCommand实现的参数值。

即执行栈下面方法中的参数值为“橙色”,

  public void Execute(object parameter)
  {
     _execute(parameter);
  }

我想弄清楚的是如何创建 RelayCommand ACommandWithAParameter 属性,以便它可以使用 XAML 中定义的 CommandParameter“Orange”调用 CommandWithAParameter 方法。

有没有办法做到这一点?

我为什么要这样做? “即时本地化”的一部分 在我的特定实现中,我想创建一个可以绑定到多个按钮的 SetLanguage RelayCommand。我想将两个字符语言标识符(“en”、“es”、“ja”等)作为 CommandParameter 传递,并为 XAML 中定义的每个“设置语言”按钮进行定义。我想避免必须为每种支持的语言创建 SetLanguageToXXX 命令,并将两个字符语言标识符硬编码到 ViewModel 中的每个 RelayCommand 中。

【问题讨论】:

  • 对这个问题提供的答案都没有帮助我创建一个 RelayCommand 对象来与需要参数输入的方法进行通信。如果有人有类似的问题,这个帖子帮助了我:stackoverflow.com/questions/5298910/…

标签: .net wpf data-binding mvvm lambda


【解决方案1】:

我不明白为什么您首先要指定 lambda 的额外复杂性。为什么不这样做:

if (_aCommandWithAParameter == null)
{           
    _aCommandWithAParameter = new RelayCommand<object>(CommandWithAParameter);
}

private void CommandWithAParameter(object state)
{
    var str = state as string;
}

【讨论】:

  • 只读操作 _execute;只读谓词 _canExecute; public RelayCommand(Action execute) : this(execute, null) { } public RelayCommand(Action execute, Predicate canExecute) { if (execute == null) throw new ArgumentNullException("execute"); _execute = 执行; _canExecute = 可以执行; Action 是一个委托,在调用构造函数时需要一个 lambda 表达式。不知道为什么,否则我会收到编译器错误。
  • 因为它是 Action,而不是 Action。更新了我的帖子以澄清。
  • 对第一条评论中的间距感到抱歉。无论如何,关键是由于 RelayCommand 构造函数中的参数参数,需要 lambda 表达式。即 public RelayCommand(Action execute) : this(execute, null)。由于 RelayCommand 的构造函数需要一个委托,因此在创建新的 RelayCommand 时,必须使用我的帖子中显示的 lambda 表达式。在 lambda 表达式右侧使用的方法中的参数类型确实改变了在创建 RelayCommand 时必须使用 lambda 表达式这一事实。
  • 没有参数就不用lambda表达式了吧?否则它不会为我编译。
  • RelayCommand 构造函数采用Action&lt;object&gt;,因此您传递给它的方法必须与该委托匹配。我上面的代码示例中的那个,因为它需要一个对象参数。如果您的方法不采用对象参数,那么最简单的转换方法确实是使用 lambda:new RelayCommand(_ =&gt; MyMethod())(下划线是未使用的 lambda 参数的常规名称)
【解决方案2】:

您将 lambda 中的参数传递给命令,如下所示:

if (_aCommandWithAParameter == null)
{           
    _aCommandWithAParameter = new RelayCommand(               
        param => this.CommandWithAParameter(param)
        );        
}

【讨论】:

  • Paul,当我使用您上面建议的语法时,我收到编译器错误“无效表达式')'”。
  • ** 字符用于表示强调 - 它们不应出现在您实际剪切和粘贴的代码中。
  • 保罗谢谢你是对的。我应该意识到两边的**是为了强调。您的解决方案有效。我将 Kent 的解决方案标记为答案,因为它更简单(或者我应该说没有 lambda 表达式更容易理解)。
  • 您是否介意编辑您的答案以显示 = new RelayCommand(param => this.CommandWithAParameter(param))。我认为这会让其他人更容易理解,他们不会犯我犯的同样的剪切和粘贴错误。我猜我没有足够的声望点来编辑其他人的答案,否则我会自己做。
【解决方案3】:

在此之前发布的任何内容都对我有用。

事实证明,RelayCommand 之后的所有答案都缺少&lt;object&gt;

这对我有用:

public RelayCommand<object> OKCommand
{
    get
    {
        if (_okCommand == null)
            _okCommand = new RelayCommand<object>(OkCommand_Execute);
        return _okCommand;
    }
}
private RelayCommand<object> _okCommand = null;

private void OkCommand_Execute(object obj)
{
    Result = true;
}

如果要使用CanExecute 方法,请使用以下代码:

_okCommand = new RelayCommand<object>(OkCommand_Execute, OkCommand_CanExecute);

private bool OkCommand_CanExecute(object obj) { }

【讨论】:

    【解决方案4】:

    这是命令参数的简单解决方案,因为我正在寻找有关该主题的帮助。我在网上找不到任何足够简单的东西。当您使用中继命令时,以下解决方案效果很好。 我有一些超链接需要获取使用命令参数单击的 url 值。

    第 1 步:在您的中继命令中,创建一个简单的属性来保存参数对象的值。您可以将其命名为 parametervalue 或您喜欢的任何名称。

    public object ParameterValue
    {
      get;
      set;
    }
    

    第二步:在 RelayCommand 类的 Execute 方法中,将上面创建的值或属性设置为 Execute 方法的参数。

    readonly Action<object> m_execute;       // Action to execute
    
    public void Execute(object parameter)
     {
       this.ParameterValue = parameter;
       m_execute(parameter);
     }
    

    第 3 步:现在您可以将 xaml 中的 CommandParameter 绑定到执行命令时要检索的任何值。 示例:

    <TextBlock>
      <Hyperlink Command="{Binding Path=NavigateUrlCmd}"
                 CommandParameter="{Binding ElementName=tbwebsite, Path=Text}">
        <TextBlock Name="tbwebsite" Text="{Binding Path=website}"/>
      </Hyperlink>
    </TextBlock> 
    

    如果你有一个名为 chickenCommand 的命令,在执行时你可以访问参数: chickenCommand.ParameterValue

    我希望这对某人有所帮助。感谢您之前的所有帮助。

    【讨论】:

      【解决方案5】:

      我只是想推销我的观点,看看这是否有效......

      http://mywpf-visu.blogspot.com/2009/12/relay-command-how-to-pass-parameter.html

      【讨论】:

        【解决方案6】:

        由于编译错误,我无法替换对 lamda 表达式的方法名称的引用。显然,并且毫不奇怪,不能使用非静态方法名称引用来代替 lambda。我几乎不认为它是“增加的复杂性”。持续传递 lamdas 对我来说很有意义。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2010-12-19
          • 1970-01-01
          • 1970-01-01
          • 2014-10-30
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多