choose the Best Practice for command in MVVM

Topics: Prism v2 - WPF 3.5
Jul 22, 2009 at 10:57 AM

Hi,

Sorry, this topic doesn't really concern Composite WPF but I think, that it can be usefull for other person than me.

I am a bit confusing about the commanding aspect in WPF with the pattern MVVM. I am currently looking for some documentation and I found different possibility.

I don't know which one I should use in order to have the "best practice".

 

First : RelayCommand

 

private RelayCommand r_launchModuleCommand;

public ICommand launchModuleCommand
{
get { if (r_launchModuleCommand == null)
{
r_launchModuleCommand = new RelayCommand(param => CanLaunch(), param => Launch());
}

return r_launchModuleCommand;
}
}


private bool CanLaunch()
{
return Auth;
}

/// <summary> /// Loads the data from database. /// </summary> private void Launch(string name)
{
Bootstrapper.LoadModule(name);
}


All of these are in the ViewModel and in the xaml : Command="{StaticResource launchMemberModuleCommand}"
The problem with this method, I don't know how to have a parameter with a CommandParameter in the xaml.

Secondly : RoutedCommand
public static readonly RoutedCommand Foo = new RoutedCommand();

void Foo_CanExecute(object sender, CanExecuteRoutedEventArgs e)
        {
            // The Window gets to determine if the Foo 
            // command can execute at this time.
            e.CanExecute = true;
        }

        void Foo_Executed(object sender, ExecutedRoutedEventArgs e)
        {
            // The Window executes the command logic when the user wants to Foo.
            MessageBox.Show("The Window is Fooing...");
        }

Problem : these methods are in the code behind and if I understand MVVM, the less code we have in the code behind, the better is.


Thirdly :ICommand
public ICommand launchModule { get; private set; }
       
//Constructor
        public ShellViewModel()
        {
            this.launchModule = new DelegateCommand<string>(OnlaunchModule);         
        }

private void OnlaunchModule(string name)
        {
            Bootstrapper.LoadModule(name);        
        }


with in the xaml :
xmlns:command="clr-namespace:Microsoft.Practices.Composite.Presentation.Commands;assembly=Microsoft.Practices.Composite.Presentation"
command:Click.Command="{Binding launchModule}"
command:Click.CommandParameter="memberModule"/>

 

This one seems to be a good solution if I can add the canExecute method, but how to do this ?

Last one : the old method from MVC pattern : OnClick

private void On_Click(object sender, RoutedEventArgs e)
        {
            //Do something                  
        }

As you can see, I just want to use the canExecute method and Execute with a parameter (selected item from list, combobox or string basically).
Thank you for helping me to use a good developing practice.

Vlado

Jul 22, 2009 at 3:06 PM

Hi Vlado

A guidline for best practices is the testability of your code. Code Behind events are hard to test, so i would prefer the Commanding approach.
Whether to use RelayCommand or DelegateCommand is a question of your needs. The Relay command is a somewhat light-weight DelegateCommand.

ICommand is just an interface that is implemented by both, RelayCommand and DelegateCommand.
I prefer to use ICommand and DelegateCommand in the ViewModels, so i can use my mocking framework for testing (which requires Interfaces to be mocked).
The DelegateCommand is clearer for me than the RelayCommand.

I also use the AttachedCommandBehaviour framework from http://marlongrech.wordpress.com/2008/12/13/attachedcommandbehavior-v2-aka-acb/
It provides nice Event wrapping for Controls events. This way I can handle events and commands in a consistent manner.

Hope this helps. Regards

 

Jul 22, 2009 at 3:47 PM

Hi,

thanks for this quick answer :)

So finally, I didn't have a wrong idea. I implement the DelegateCommand already. I just have to find a wayt to use the canExecute method with the delegate. I am still a newbie concerning C# syntax.

I was looking at this website this morning, I will download the example in order to understand a little bit more by trying the sample.

Vlado

 

Jul 22, 2009 at 7:49 PM

Hi Vlado,

In Prism-v2, the approach you mentioned for the delegate command is for Silverlight Applications. In WPF applications you can simply use the Command and CommandParameter properties in XAML. The same approach is valid for WPF RoutedCommands (since they use the same interface).

<Button AutomationProperties.AutomationId="SaveButton" Grid.Row="6" Grid.Column="1" Content="Save" Command="{Binding SaveOrderCommand}" CommandParameter="..."/>

As you said, one of the goals of the MVVM pattern is not having much code behind in the view, to increase testability among other things. For this reason, the view Model is set as the DataContext of the view, and bindings in XAML to commands are performed, thus avoiding the code behind (you can check any of the Quickstarts or RI that use command to check how this is done).

Finally, to add a can execute method to the DelegateCommand<T>, you can use code like this:
  new DelegateCommand<MyType>(Execute, CanExecute); //Execute and CanExecute are methods in the ViewModel where the command is created.

 

The following might provide some more information to you about commands:

Please let me know if this helps.

Damian Schenkelman
http://blogs.southworks.net/dschenkelman

Jul 23, 2009 at 8:51 AM

As usual, thanks a lot for this answer. I really like this discussion thread in codeplex, you are doing a great job.

In fact, I find yesterday that the problem came from my control. I am using the ribbon office control and I can't use  this method. (I am looking for a fix at this time :)) 

 

I will now clean my code with this syntax. Thanks

 

Vlado