【问题标题】:Relaycommand and parameterless execute method中继命令和无参数执行方法
【发布时间】:2012-08-05 12:01:02
【问题描述】:

我目前正在学习 WPF 和 MVVM,我想我掌握了大部分内容以及它是如何工作的,但是我在使用 RelayCommand(或 DelegateCommand)时遇到了一些我不理解的东西。我认为这与代表的工作方式有关。

请注意,下面的代码目前都只是在测试解决方案中,所以没有实时代码。此外,我正在考虑对不需要参数(例如 close)的命令执行此操作,并了解其工作原理。

因此,如果我采用 Josh Smith 创建的 RelayCommand (http://msdn.microsoft.com/en-us/magazine/dd419663.aspx#id0090030),我可以设置如下命令:

RelayCommand updateTextContentCommand;

public ICommand UpdateTextContentCommand
{
    get
    {
        if (updateTextContentCommand == null)
        {
            updateTextContentCommand = new RelayCommand(
                param => this.UpdateTextContentCommand_Execute());
        }
        return updateTextContentCommand;
    }
}

使用这个执行方法:

public void UpdateTextContentCommand_Execute()
{
    this.TextContent = DateTime.Now.ToString();
}

我使用了一个简单的 TextBlock 绑定来查看结果,并将命令绑​​定到一个按钮。这工作正常。我没有得到的是使用 lambda 表达式来创建命令。 Action<object> 需要一个参数不是吗?那么为什么这段代码有效呢?

如果我把上面的代码改成

if (updateTextContentCommand == null)
{
    updateTextContentCommand = new RelayCommand(
        this.UpdateTextContentCommand_Execute());
}

我收到以下错误:

*“MVVM.RelayCommandTesting.Framework.RelayCommand.RelayCommand(System.Action)”的最佳重载方法匹配有一些无效参数

参数 1:无法从 'void' 转换为 'System.Action'*

并在 Execute 后删除 () 会出现此错误:

参数 1:无法从“方法组”转换为“System.Action”

但是如果我像这样更改代码:

if (updateTextContentCommand == null)
{
    updateTextContentCommand = new RelayCommand(
        this.UpdateTextContentCommand_Execute);
}

public void UpdateTextContentCommand_Execute(object param)
{
    this.TextContent = DateTime.Now.ToString();
}

它符合并运行良好。如果我将视图更改为使用 CommandParameter,则可以使用 param 使用此方法设置文本内容,但如果我使用 lambda 样式,则必须将参数传递给该行,因此它类似于 param => this.UpdateTextContentCommand_Execute(param)

在我的测试中,我对 CommandParameter 值进行了硬编码,但我猜它很可能是绑定到真实系统中 ViewModel 属性的数据,因此您可以以 lambda 样式传递参数。

谁能解释一下为什么无参数版本适用于 lambda 样式?

感谢您花时间阅读本文。

下面的问题似乎也有一些关于 lambda 的问题,但我看不出它回答了我的问题。

Passing a parameter using RelayCommand defined in the ViewModel (from Josh Smith example)

【问题讨论】:

  • +1 表示您已经尝试过的详细问题。
  • 干杯。在发布问题时,我总是努力尝试,因为我发现这样的问题在我寻找答案时很有用。

标签: .net wpf mvvm lambda


【解决方案1】:

构造函数参数是一个具有以下签名的委托:

void MethodName(T parameter)

其中参数的类型为 T(在 RelayCommand 的情况下,其类型为 system.Object

这段代码:

param => this.UpdateTextContentCommand_Execute()

是一个lambda 表达式,它本质上扩展为:

void AnonymousMethod(object param)
{
    this.UpdateTextContentCommand_Execute();
}

所以在这种情况下,您正在传入一个参数 (param),您只是没有使用它。 如果您理解了这一点,那么您现在应该明白为什么您的其他示例的行为方式会如此。

示例 1

if (updateTextContentCommand == null)
{
    updateTextContentCommand = new RelayCommand(
        this.UpdateTextContentCommand_Execute());
}

你在这里调用返回 void 的方法。构造函数期望与 Action<T> 委托匹配的东西,因此会出现错误。

示例 2

如果你然后像这样删除括号:

if (updateTextContentCommand == null)
{
    updateTextContentCommand = new RelayCommand(
        this.UpdateTextContentCommand_Execute);
}

这有点像订阅一个事件:

myObject.myevent += new Action<object>(this.UpdateTextContentCommand_Execute);

可以简写为:

myObject.myevent += this.UpdateTextContentCommand_Execute;

因此构造函数接受任何具有匹配Action&lt;T&gt;委托签名的签名的方法,即

void UpdateTextContentCommand_Execute(object parameter)

您的方法具有以下签名:

void UpdateTextContentCommand_Execute()

如您所见,签名不匹配,因此编译器会报错。

当您更新 UpdateTextContentCommand_Execute 方法以接受对象参数时,它的签名现在匹配,这就是它现在工作的原因。

【讨论】:

  • 谢谢,您在示例方法 (AnonymousMethod) 中使用的方法对我来说一切就绪。我认为这有点像“只见树木不见森林”。我没有太多地使用 lambda 表达式,但我对 Linq 做了一些工作。我只是不想看到连接。
  • 我遇到了完全相同的问题。当我有那个“啊哈”的时候,一切都到位了,突然 lambda 表达式变得更容易理解了。我很高兴我能够以一种对其他人有所帮助的方式来表达我的经历。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-03-30
  • 2020-06-19
  • 2016-08-20
  • 2020-03-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多