Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Delegates, Actions, Events, Lambda expression and MVVM

I have spent few days trying to understand WPF and MVVM. It is going very slowly mostly because I have some lack of knowledge in terms of events and stuff. Here bellow I will try to explain my understanding of all this things:


Method – this one is simple and I don't think it needs any explanation. Basic ingredient in any program.

Delegate – the way I see it is pointer on method. I can think of only few applications where I would want to use it over a method.

Action – that one is even trickier. Information I have managed to find say that it is a delegate that doesn't return value... so is it just pointer on void method? I don't see point of that

Event – this one I don't get at all. It was being explained with delegate and I didn't understand how does it work and what is it for. Note I was using events writing winforms applications but it was just choosing desired event from the list.

Event handler – even more unclear.

Lambda expression – also yet another way of using method. Again I understand it doesn't return anything, I can pass some argument in it, but still aint much different from void method. I have seen some applications like when using LINQ but I still don't understand how it works.


I would like to start by saying that I understand basic construct of MVVM, what is doing what and so on. Issue I have is that I don't understand some of the code, how does it work and therefore I can't write anything actually on my own. I will be using some tutorials as example so here it goes:

S1: https://msdn.microsoft.com/en-us/magazine/dd419663.aspx#id0090030

S2: http://social.technet.microsoft.com/wiki/contents/articles/18199.event-handling-in-an-mvvm-wpf-application.aspx

What I am expecting from you guys is some guidance or explanation how can I approach and understand those thinks to make them at least a little less scary for me. Here I will place some examples that will hopefully show you what kind of problems I have.


1) First one comes from S1 from well known RelayCommand class:

    public event EventHandler CanExecuteChanged
    {
        add { CommandManager.RequerySuggested += value; }
        remove { CommandManager.RequerySuggested -= value; }
    }

I know what it is suppose to do (name speaks for itself). But I don't understand how this thing works? How it knows when to make something executable and when not. What are exactly those add and remove “commands”? I tried to read about it but it didn't help.

2) Another example form S1:

    #region CloseCommand

    /// <summary>
    /// Returns the command that, when invoked, attempts
    /// to remove this workspace from the user interface.
    /// </summary>
    public ICommand CloseCommand
    {
        get
        {
            if (_closeCommand == null)
                _closeCommand = new RelayCommand(param => this.OnRequestClose());

            return _closeCommand;
        }
    }

    #endregion // CloseCommand

    #region RequestClose [event]

    /// <summary>
    /// Raised when this workspace should be removed from the UI.
    /// </summary>
    public event EventHandler RequestClose;

    void OnRequestClose()
    {
        EventHandler handler = this.RequestClose;
        if (handler != null)
            handler(this, EventArgs.Empty);
    }

    #endregion // RequestClose [event]

Again I know what it is suppose to do, I even understand what is basically happening here but I don't see where this “thing” is actually doing something. OnRequestClose() is just creating handler that in my eyes doesn't do anything to close whatever it is suppose to close. Problem is that if I even don't see where command is executed how can I write my own commands.

3) I think this will be last example, this time from S2:

public ViewModel()
{
    _clickCommand = new DelegateCommand<string>(
        (s) => { /* perform some action */ }, //Execute
        (s) => { return !string.IsNullOrEmpty(_input); } //CanExecute
        );
}

Here problem is pretty simple. It is creating command using RelayCommand ctor (or at least it's version in this project, here called “DelegateCommand”). I don't understand those (s) and use of lambda. What is it for?


Of course that isn't everything I have problem with but I think that will give idea what is my problem to anyone willing to help. I tried to explain my problem as best as I can and I would really appreciate any help or guidance. Maybe I am expecting to much from myself but I feel like I need to know all that stuff in order to write anything serious.

Anyway thank you all in advance for any help.

like image 434
Bielik Avatar asked Sep 28 '22 02:09

Bielik


1 Answers

A long answer for your broad question.

Let me dig into Events and EventHandler first using a simple approach

Suppose there is a big function organized in your city which will host many famous people from your country.

Let's consider three guest's for this example
Guest one is a person who is unknown by other guests
Guest two is a famous person from your area and very few people know
Guest three is very famous across your country

Consider the following assumptions

Nobody is waiting for guest one (0 EventHandler)

There are four people who are waiting for guest two (4 EventHandler's each person is an event handler waiting to greet)

There are three security personnel and 10 guests (out of which one person is also waiting for guest 2) waiting for guest 3 (13 EventHandler's)

Scenario 1 When guest one arrives at the venue (Event raised) nothing happens

Scenario 2 When guest two arrives at the venue (Event raised) the four people move towards him/her and give greetings

Scenario 3 When guest three arrives (Event) you will see security forces providing cover and ten people move towards him/her and give greetings

Simple points to be observed
1. Event is just a notification that something has happened (like a delegate with a method signature)
2. EventHandler is an action as to what happens when a specific event has happened ( a method which implements the method signature defined by the delegate)
3. One event can have many eventhandlers (e.g.. scenario 2,3). Hence the syntax += in the below code sample

The below code will answer some of your basic questions

class Program
{
    static void Main(string[] args)
    {
        var test = new Example();
        Console.ReadLine();
    }
}


class Example
{
    //This is the event definition
    delegate void ActionDelegate(string input1, string input2);

    // Two event handler which implements the signature of the event
    void ActionMethod(string a, string b)
    {
        Console.WriteLine(a + " " + b);
    }
    void ActionMethod2(string c, string d)
    {
        Console.WriteLine("Wow one more function called with parameter {0} and {1}", c, d);
    }

    delegate Tuple<string, string> LamdaDelegate(string input1, string input2);
    public Example()
    {
        //Did not declare any delegate member variable explicitly.
        //Clean and easy to understand
        Action<string, string> action = ActionMethod;

        // Had to define the delegate with method signature explicitly before using it
        ActionDelegate actionDelegate = ActionMethod; 
        actionDelegate += ActionMethod2; // Attaching more event handlers to the event

        //The below lambda expression implicitly means that it will take two inputs each of type string
        // and does not return anything. 
        //The type information is implicitly derived from the method signature of the delegate
        actionDelegate += (a, b) => Console.WriteLine("Called using lambda expression");


        //Below is a Lambda expression in which s and e each is of type string 
        //Since the return type of the delegate is Tuple<string,string> the same is returned by the expression
        //Lambda expression is using a delegate without defining a delegate explicitly. 
        LamdaDelegate myTuple = (s, e) => { return Tuple.Create(s, e); };

        //The above Lambda can be rewritten as
        myTuple += delegate (string a, string b) { return Tuple.Create(a, b); };

        //Invoking the event handlers. The event handlers are executed automatically when ever the event occurs 
        action("Hi", "called from action");
        actionDelegate("Hi", "called using explicitly defined delegate");
    }
}

Why should we use delegates?
In the above example you saw that the ActionMethod is used by two different delegates(read Event). Without delegates the above example would be dirty and unreadable.
The above example also shows Action which simplifies the need to define delegates explicitly.

Now comming to Commands
In MVVM the traditional event is replaced by Command and the event parameters (read delegate method signature) is replaced by CommandParameter

In your 3rd question the DelegateCommand has a type parameter which is string. So the (s) you see is a variable which stores the input string sent from UI. Now it is upto you to decide if you want to use the input (s) or ignore it all together. In the CanExecute part you can see that even when the input (s) is passed it has ignored it and uses the other member variable _input.

The 2nd question an event RequestClose is defined which is attached an event handler in Figure 7 of the link. Also observe that in the same figure the MenuItem is bound to the CloseCommand in the ViewModel.
So now when you click on the MenuItem the CloseCommand is invoked and it then calls the function OnRequestClose. The first thing this function checks is that is there anyone interested(read listening) in the event RequestClose which the MainWindow is listening and hence calls the window.Close()

For more clarification please do let me know.

EDIT

The code example above was just for Action<T> and delegate.

In layman terms let me put it this way

If I want to do something based on some external action I would use Event . I will just define an event and wire it up to an EventHandler and just wait for the action to occur. (In the example above I don't know when will the guest arrive but whenever they do arrive the EventHandler will respond automatically)

On the other hand I will use delegate if I want to call single/multiple functions simultaneously based on some internal condition defined in the code. In the code example above you can see that I had to invoke the delegate manually.

Please ignore the Tuple as it is just a return value with no actual importance.

EDIT 2

The scenario (_) or (s) is similar. Both mean that you will get a parameter as an input but in the first scenario the developer is trying to say that this parameter will not be used or ignored while in the (s) they intend to use it

You can't use just () as this means that the lambda expression does not contain any input parameter which is wrong since the definition says that it will receive a string as an input.

like image 97
Sandesh Avatar answered Oct 03 '22 23:10

Sandesh