6

I need a bit of help to understand the relationship between a viewmodel and a command, and the responsibility of the viewmodel.

I'll try to give an example (using Caliburn Micro).

I have a viewmodel class, a command class and a view with a Save button.

public class EditViewModel : Screen
{
    public bool CanSave
    {
        get { return IsDirty; }
    }

    public void Save()
    {
        var command = new SaveCommand(this); // command gets reference to VM
        command.Execute();
    }
}

public class SaveCommand
{
    private readonly EditViewModel _viewModel;

    public SaveCommand(EditViewModel viewModel)
    {
        _viewModel = viewModel;
    }

    public void Execute()
    {
       var work = _viewModel.Work;
       ..
       _viewModel.IsDirty = false;
    }
}

When the user click Save. Save() method is called and spins up a command that saves the work.

Now my question is, should the command have a reference to the viewmodel?

No) The viewmodel will have to pass the work to the command, which will have to pass the save result back to the viewmodel, which will update itself.

Yes) The command needs a reference to the viewmodel and properties needs to be public set-able.

No seems like the cleanest way, but also requires extra work, when the work or result aren't a simple bool or similar.

I guess the root it all is. What is the relationship between a viewmodel and it's command and the responsibility of the viewmodel ?

Is there a strong 1:1 "friend" relationship between the view-model and it's command, where code has just been moved to another class. So there is nothing wrong with the command having direct access to the viewmodel.

Another understanding, the viewmodel is a very simple class, almost only with properties and contains little logic. So the logic should be in the command.

Or the viewmodel is pretty smart and should contain application-logic. Commands are really only needed when there are either too many in one viewmodel or they are a bit complicated otherwise the command code can stay in the viewmodel.

I'm just rambling I guess, please help me out to understand the viewmodel and what it's responsibility is?

  • This is an excellent question...did you edit it since you originally posted or did I just miss part of the question when I answered. I'm going to update my answer shortly...with an excerpt from my book. – Michael Brown Aug 13 '13 at 18:14
  • No edit tag, so didn't touch it :-) – Karsten Aug 16 '13 at 7:03
6

The command should be on the ViewModel.

In MVVM, the ViewModel is the thing that should contain all of the logic that drives the view. The view is the simple class - just a collection of UI controls whose state is bound to properties on the ViewModel.

Josh Smith wrote a really good intro to MVVM that should clear things up for you.

  • Using Caliburn, commands are not properties, but methods – Karsten Aug 13 '13 at 7:46
3

MVVM inherits directly from the original Smalltalk MVC pattern as defined by Trygve Reenskaug. Just like MVC is highly misunderstood, MVVM is as well. In the original definition, MVC consisted of an conceptual model (which we refer to nowadays as a Domain Model) that contains the data and logic that powers an application, a View which provides a visual representation of that conceptual model, and a Controller which listens to events on the view and handles them as operations within the Model.

What people forget is that the Smalltalk environment was practically the first GUI in existence. This is the very project at Xerox that Jobs "emulated" for the Lisa (and which Microsoft later leveraged for Windows). Smalltalk had a very low-level user interface system, similar to programming the Win32 API directly. The controller was responsible for listening to the message pump and converting the messages that came to the UI into logical operations. There were no widget libraries when the MVC pattern was first conceived.

Fast forward a few years and Smalltalk is a commercial product (VisualWorks) with widgets and a new pattern has emerged: MMVC, this is MVC with two models: the Domain Model which is what we understand it to be; and the Application Model which more or less is a model specifically for the application itself, containing concepts that are important to the application but not to the domain.

Let me point to an interesting point in the C2 Wiki topic on MMVC (emphasis mine):

So what, you say. Well, here's what. As a point of general principle, people who talk about MVC architecture (such as people in the J2EE and JSP communities) should take it upon themselves to understand the historical meaning and implications of the terms they use, so as to eliminate confusion about WhatsaControllerAnyway, and to be aware that ModelViewController often means ModelModelViewController in the original Smalltalk implementation of the paradigm. In fact, a case could probably be made that many of the responsibilities allocated to the "controller" (in the Jacobsonian connotation of the term) were probably allocated to ApplicationModels in ModelModelViewController architecture.

The MMVC architecture gave the application model responsibilities that were normally assigned to the controller. Because of the introduction of widgets in VisualWorks that knew things like "I'm a button and someone clicked me". Controllers did not need to contain as much logic that they used to. The dispatch of operations gravitated toward the Application Model and away from the Controller.

MVVM is MMVC without a separate controller. The ViewModel should contain logic within it, but only enough to interpret a command and dispatch it to the Model for further handling. As I mentioned before, Caliburn does a lot of wiring for you by convention. So instead of having to register a relay command and have it resolve to the method, Caliburn looks for a method on your ViewModel called Save and wires up a command for you that is registered against the Button with an X:Name of Save, pointing it to your Save method.

2

I'm going to reword what Mike Brown said.

The main point of commands is to allow easy databinding from DataContext to active controls, like buttons. So you create a command class, expose it as property and bind it to button. This button will then call Execute when pressed. This is simply because you cannot bind methods directly. And also allows you to have CanExecute in one place as what is executed.

But with Caliburn.Micro, it allows you to bind methods directly through convention. It actually creates a command internally for you. So with Caliburn.Micro, custom commands are practically unnecessary.

  • Caliburn.Micro is the way to go. Saves you a lot of time. – juFo Sep 18 '15 at 7:57
1

Caliburn uses "conventions" to Autowire functions as commands to command targets. So your Save function on your ViewModel gets neatly wrapped up into a command behind the scenes (read the section on Action Matching in the Caliburn documentation on Conventions) to learn how it works.

Essentially, you can skip creating commands at all, because caliburn uses conventions to remove some of the ceremony of MVVM for you.

  • Sorry I don't get it, it seems to me that what you are saying is exactly the same thing I have shown in my example? I don't want to skip creating commands, I like thin view models. – Karsten Aug 13 '13 at 7:36
  • Caliburn does all of this for you automatically. I don't use it heavily so I'm not sure how you opt out of the convention based model. Do you want to create separate command objects to re-use in different view models? If so, they cannot make use of any of the values of the vm itself. – Michael Brown Aug 13 '13 at 18:11
0

Here's an example of your view model class using MVVM Light Toolkit:

public class EditViewModel : ViewModelBase
{
    public EditViewModel()
    {
        SaveCommand = new RelayCommand(noParameter => Save());
    }

    private void Save()
    {
        // Save code goes here.
    }

    public static ICommand SaveCommand { get; private set; }
}

The RelayCommand class will relay all uses of the SaveCommand property to the Save() method in the view model class. The command itself does not need to reference the view model class since it is a member of the view model class.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.