C# Icommand syntax

457 views Asked by At

I'm learning C#, and I just came across events, I'm reading the following code:

class ACommand : ICommand
{
    public ACommand()
    {
        Model.Duck.Weight.PropertyChanged += (sender, args) =>
        {
            if (CanExecuteChanged != null)
            {
                CanExecuteChanged(this, new EventArgs());
            }
        };
    }

    public bool CanExecute(object parameter)
    {
        //some code
    }

    public event EventHandler CanExecuteChanged;

    public void Execute(object parameter)
    {
        //some code
    }
}

I understand most of it, but what I don't really get is the part:

Model.Duck.Weight.PropertyChanged += (sender, args) =>
{
    if (CanExecuteChanged != null)
    {
        CanExecuteChanged(this, new EventArgs());
    }
};
  1. Does this code just tells the program that whenever the ducks wieght changes, it should execute CanExecute methode, and warn everybody who is bound on this command?
  2. Also, when the duck changes, should I unsubscribe from the old duck and subscribe to the new duck? Because If I don't unsubscribe and only add a subscription to the new duck, the old one will still get notified when something changes,or am I wrong? (Can anybody show me how I unsubscribe from the old duck, when the Model.Duck changes? Thank you.
3

There are 3 answers

6
LInsoDeTeh On

PropertyChanged is the name of the event triggered by Model.Duck.Weight. With += you're adding a receiver to the event. You could add an existing function here, like Windows Forms would do:

Button1.Click += this.Button1_Click;

with

void Button1_Click(object sender, EventArgs e)

But in your case, instead of giving a concrete function, an anonymous function is added as a handler to the PropertyChanged event:

(sender, args) => { //do something }

Inside the function (where my //do something is), you fire your own event, CanExecuteChanged. The check for null makes sure, someone else has added an event handler to your event and if so, you just fire it.

PS: Unsubscribing works exactly the other way around:

PropertyChanged -= <the function handling the event>
2
Thomas Levesque On
  1. Does this code just tells the program that whenever the ducks wieght changes, it should execute CanExecute methode, and warn everybody who is bound on this command?

Yes; it triggers the CanExecuteChanged method so that controls bound to this command will re-evaluate whether or not the command can execute.

  1. Also, when the duck changes, should I unsubscribe from the old duck and subscribe to the new duck? Because If I don't unsubscribe and only add a subscription to the new duck, the old one will still get notified when something changes,or am I wrong? (Can anybody show me how I unsubscribe from the old duck, when the Model.Duck changes? Thank you.

It's not the duck that is notified when CanExecuteChanged is raised, it's the controls that are bound to that command.

If Model.Duck can change, yes, you should unsubscribe from the old one and subscribe to the new one. But I don't have any context for your code so I don't know what Model.Duck is exactly. It looks like example code, not real-world code.

1
Mike Eason On

The sample code that you provided burns my eyes.

I will not answer your questions directly, as they have already been answered by other people in this thread. However, I will offer some suggestions.

Firstly:

Model.Duck.Weight.PropertyChanged += (sender, args) =>
    {
        if (CanExecuteChanged != null)
        {
            CanExecuteChanged(this, new EventArgs());
        }
    };

No. No no no no. No. No!

Remember, the MVVM design pattern is about keeping things decoupled, your command should never ever, ever need to subscribe to the property changed event on a model, I literally cannot think of any scenario where you would need to do this.

It is clear that the reason behind subscribing to the PropertyChanged event is because you need to refresh the binding to CanExecuteChanged. Which makes sense, however, there is a better way.

Replace this:

public event EventHandler CanExecuteChanged;

With this:

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

"What the hell is this?" I hear you ask. Well, this effectively refreshes the CanExecuteChanged under certain UI conditions. So if your model's PropertyChanged is called, then magic will happen, and the application will work out which commands need to be refreshed. You'll have to research further into this to learn more. Essentially, this allows you to remove that nonsense I mentioned earlier with subscribing to the PropertyChanged event.