2
votes

This is a specific question about the MVVM pattern best practice. I'm using MvvmLight Library. It goes like this: My model, say "Flight", implements some business logic that can start, pause and stop flights via methods. Each method does its logic to make the functionality happen whether it's playing stopping or pausing the flight. One important variable that changes is a status enum which indicates the flight status - playing, stopped, or paused. As said the status variable (and property) are defined in the Model. On the other side the flight class is wrapped by a ViewModel class which contains a Status property that wraps the status variable in the flight model, and also RelayCommands that connect to the flight model play stop pause methods.

Here the problem begins: When I execute one of the commands through the view, it executes the method in the model so that the status variable itself changes directly, but it only changes in the model.. The status property in the ViewModel doesn't know whether the wrapped variable have been changed, as it was changed directly... That means if some view element is binded to the status property, it won't change upon command execution..

I know several means to solve this but I'm asking for a fair solution that won't break the MVVM pattern (like using INotifyPropertyChanged in the flight class in the Model )

5

5 Answers

5
votes

There is no magic bullet solution to this type of problem. Your ViewModel and Model need to be designed in a way that allows the information to propagate to the View; if this is not possible, then the design is flawed and needs to change.

Here's a couple of things you should look into:

  • If the Model's state-modifying methods are documented to execute synchronously, create methods on the ViewModel that forward the action to the Model and then immediately query its state. Use these methods for the implementation of the RelayCommands.
  • If the Model's methods are not synchronous then there should be some mechanism available to the Model's clients to notify them when the methods have completed. This can be done through continuation callbacks, events, or perhaps even with INotifyPropertyChanged.
4
votes

As you mentioned above, your ViewModel should wrap Model at the following way:

class Model
{
   public int State{get;private set;}
   public void Fly()
   {
      State=1;
   }

   public void Stop()
   {
      State = 2;
   }
}

class ViewModel : ViewModelBase
{
   int State{ get{ Model.State;}}
   ...
   OnFlyCommand()
   {
      Model.Fly();
      NotifyPropertyChanged("State");
   }
}
3
votes

You could just call OnNotifyPropertyChanged just after the ViewModel executed the method on Model. That's not very elegant, but you just can't get any simpler without refactoring your Model class.

1
votes

Do you know what properties have changed after the command is executed? I mean, can you explicitly raise change notification on specific set of properties or the set of modified properties is changing?

In the former case you invoke command and raise the event for those properties explicitly:

command.Execute();
NotifyPropertyChanged("PropA");
...
NotifyPropertyChanged("PropN");

In the second case you can either raise change notification event for every property of the Model class using reflection or you can use a smarter solution like PostSharp.Domain.Toolkit.

1
votes

Best practice is to call viewmodel from command execution, than call model change from viewmodel, after which mark viewmodel state as changed