Relay命令和无参数执行方法

时间:2012-08-05 12:01:02

标签: .net wpf mvvm lambda

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

请注意,以下代码目前仅在测试解决方案中,因此没有实时代码。此外,我正在考虑这个不需要参数的命令,例如关闭,并了解其工作原理。

因此,如果我采用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'*

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

参数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 =&gt; this.UpdateTextContentCommand_Execute(param)

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

任何人都可以解释为什么无参数版本适用于lambda样式吗?

感谢您花时间阅读本文。

以下问题似乎也有关于lambda的一些问题,但我不认为它回答了我的问题。

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

1 个答案:

答案 0 :(得分:9)

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

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;

因此构造函数接受任何具有与<{1}}代理签名匹配的签名的方法,即

Action<T>

您的方法具有以下签名:

void UpdateTextContentCommand_Execute(object parameter)

正如您所看到的那样,签名不匹配,因此编译器会抱怨。

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