Search code examples
c#wpfmvvmmvvm-lightcommand-pattern

ICommand implementations in a separate classes, using only MVVM Light?


We have a large-ish app with a ribbon. The ribbon buttons are all bound to commands in my main view model (the data context of the main app window).

The constructor for MainViewModel is starting to grow as we create lots of RelayCommands (bound to the various ribbon commands). It looks something like this:

    public MainWindowViewModel()
    {
        this.OpenProjectCommand = new RelayCommand(() =>
            {
                 // buncha code
            });

        this.ProjectTypesCommand = new RelayCommand(() =>
            {
                // more code
            });

        this.NewSectionCommand = new RelayCommand(() =>
            {
                // code code code...
            });
        // ... only three ribbon buttons down, this is gonna get huge...
    }

I'd prefer to have separate classes implementing each of the commands, rather than tons of inline code in MainViewModel's constructor. (Or creating lots of delegates in the MainViewModel, e.g. OpenProject, CanOpenProject, and then passing in references to them to the RelayCommand constructors).

Why don't I simply implement ICommand in a CommandBase and then create separate commands? Because I want to be "standard friendly" as per this question.

Is there a standard ICommand implementation I can use so that my commands are in separate classes?

I'd prefer not to add more MVVM frameworks into the mix since I'm already using MVVM Light. But I also don't want to reinvent the wheel.

Update: MainViewModel.cs doesn't need to be cluttered with scores of #regions or command methods. Extension methods aren't a good fit either IMHO.


Solution

  • The way I do is that I have "sub-viewmodels". For example, in the case of the MainViewModel, let's imagine that you have a PrintCommand and a CancelPrintCommand. You can have a new class called PrinterViewModel, and expose an instance of this class in the MainViewModel. Have the PrintCommand and the CancelPrintCommand in this PrinterViewModel (this also allows modular unit testing, which is neat).

    Then in XAML:

    Command="{Binding Main.Printer.PrintCommand}"
    

    Alternatively, you could do

    new RelayCommand(() => Printer.DoSomething())
    

    Does that make sense?

    Cheers Laurent