6

我目前正在学习 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'*

并删除()after 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 的问题,但我没有看到它回答了我的问题。

使用 ViewModel 中定义的 RelayCommand 传递参数(来自 Josh Smith 示例)

4

1 回答 1

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;

因此,构造函数接受具有与委托签名匹配的签名的任何方法,即Action<T>

void UpdateTextContentCommand_Execute(object parameter)

您的方法具有以下签名:

void UpdateTextContentCommand_Execute()

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

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

于 2012-08-05T12:34:55.813 回答