开发者

Need help understanding MVVM Tutorial, RelayCommand

开发者 https://www.devze.com 2023-03-10 17:43 出处:网络
I am reading http://msdn.microsoft.com/en-us/magazine/dd419663.aspx tutorial i don\'t understand what the below code is trying to do.

I am reading http://msdn.microsoft.com/en-us/magazine/dd419663.aspx tutorial

i don't understand what the below code is trying to do.

_saveCommand = new RelayCommand(param => thi开发者_如何学编程s.Save(), param => this.CanSave ); 

As defined in the realy Command class CanSave should have been a Method with a paramter since it maps to predicate therefore it's correspoding method should have a paramter same is true for action object. Please help understand.


RelayCommand uses functions (more precisely, delegates) passed into its constructor to implement CanExecute and Execute methods.

In this sample two functions are passed. First describes how to save - just call Save method on RelayCommand owner. Another one describes, how to check if saving is possible - just check current state of owner's CanSave property.

In this way you don't have to create your own Command class explicitly.

UPD:

Thanks, but my questions is Save() is of type Action, defined as Action and as per my understanding Save() should have a parameter in order to work. But some reason it is able to work even without a paramter.

Ok, let's look at it closer.

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

is equivalent of (in syntax of C# v2.0)

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

So, you create anonymous functions wrap actual methods leaving to you right to use or not to use their own parameters.

If you want to go deeper, the code above is compiled under the hood to something like:

 // 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));

Note that compiler can select other strategies for implementing delegates, depending on what values they enclose from surrounding context. E.g. if your anonymous functions referenced some local variables compiler would generate anonymous class that contained those variables and put methods in this class.


Let us simplify it

First off, RelayCommand is not part of WPF. It is a class inside the WPFlight toolkit, and we are free to write our own implementations of it. It acts as a wrapper on top of the WPF ICommand, and provides two aspects: action and predicate. The predicate part can be used, for example to enable or disable a button based on some condition. The action part shall contain the logic that should run when the command is executed.

As with most concepts, this too has many possible approaches.

Approach 1

Write explicit named methods for action and predicate. Sample code below

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
    }        
}

Approach 2

Here we shall use anonymous methods. This reduces many lines of code and makes the whole code more readable.

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;
        }
    }
}

Approach 3

Make use of lambda expressions, well, almost fully

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;
        }
    }
}
0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号