需要帮助了解MVVM Tutorial,RelayCommand

时间:2011-06-07 06:51:18

标签: wpf

我正在阅读http://msdn.microsoft.com/en-us/magazine/dd419663.aspx教程

我不明白以下代码试图做什么。

_saveCommand = new RelayCommand(param => this.Save(), param => this.CanSave ); 

正如在realy Command类中定义的那样,CanSave应该是一个带参数的方法,因为它映射到谓词,因此它的correspoding方法对于action对象应该有一个相同的参数。请帮助理解。

2 个答案:

答案 0 :(得分:2)

RelayCommand使用传递给其构造函数的函数(更确切地说,委托)来实现CanExecuteExecute方法。

在此示例中,传递了两个函数。首先介绍如何保存 - 只需在Save所有者上调用RelayCommand方法即可。另一个描述了如何检查是否可以保存 - 只需检查所有者的CanSave属性的当前状态。

通过这种方式,您无需明确创建自己的Command类。

UPD:

  

谢谢,但我的问题是Save()属于Action类型,定义为Action,根据我的理解,Save()应该有一个参数才能工作。但是有些原因它甚至可以在没有参数的情况下工作。

好的,让我们仔细看看吧。

 _saveCommand = new RelayCommand(param => this.Save(), param => this.CanSave ); 

等同于(在C#v2.0的语法中)

 _saveCommand = new RelayCommand(
     new Action<object>(delegate(object param){ this.Save(); }), 
     new Func<object,bool>(delegate(object param){ return this.CanSave; })); 

因此,您创建匿名函数包装实际方法,让您使用或不使用自己的参数。

如果你想深入了解,上面的代码将在以下内容中编译:

 // it is OK to ignore methods arguments. 
 // So, it's also OK to ignore them in anonymous methods as well
 private void Save_Anonymous(object parameter){
     this.Save();
 }
 private bool CanSave_Anonymous(object parameter){
     return this.CanSave;
 }

 ....

 _saveCommand = new RelayCommand(new Action<object>(this.Save_Anonymous), 
        new Func<object, bool>(this.CanSave_Anonymous));

请注意,编译器可以选择其他策略来实现委托,具体取决于它们从周围上下文中包含的值。例如。如果你的匿名函数引用了一些局部变量,编译器会生成包含这些变量的匿名类,并将方法放在这个类中。

答案 1 :(得分:2)

让我们简化它

首先,RelayCommand不是WPF的一部分。它是WPFlight工具包中的一个类,我们可以自由编写它们自己的实现。 它充当WPF ICommand之上的包装器,并提供两个方面:action和谓词。可以使用谓词部分,例如基于某些条件启用或禁用按钮。动作部分应包含执行命令时应运行的逻辑。

与大多数概念一样,这也有许多可能的方法。

方法1

为action和predicate编写显式命名方法。下面的示例代码

class demoViewModel
{
    string filename = "";
    private ICommand _saveCommand;
    public ICommand SaveCommand
    {
        get
        {
            if (_saveCommand== null)
            {
                _saveCommand = new RelayCommand<object>(
                     action => Save(filename),
                     predicate => CanSave(filename));

            }
            return _saveCommand;
        }
    }

    private bool CanSave(string fname)
    {
        return (!string.IsNullOrEmpty(fname));
    }

    private void Save(string fname)
    {
        SaveHelper(fname);//some logic goes inside SaveHelper
    }        
}

方法2

这里我们将使用匿名方法。这减少了许多代码行,使整个代码更具可读性。

class demoViewModel1
{
    string filename = "";
    private ICommand _saveCommand;
    public ICommand SaveCommand
    {
        get
        {
            if (_saveCommand== null)
            {
                _saveCommand = new RelayCommand<object>(
                     action => { SaveHelper(filename); },
                     predicate => { return (!string.IsNullOrEmpty(filename)); }
                     );

            }
            return _saveCommand;
        }
    }
}

方法3

充分利用lambda表达式

class demoViewModel2
{
    string filename = "";
    private ICommand _saveCommand;
    public ICommand SaveCommand
    {
        get
        {
            if (_saveCommand== null)
            {
                _saveCommand = new RelayCommand<object>(
                     (objParamForAction) => { SaveHelper(filename); },
                     () => { return (!string.IsNullOrEmpty(filename)); }
                     );

            }
            return _saveCommand;
        }
    }
}