user1549233
user1549233

Reputation:

How to implement a view model that wraps a model's property

Assume a model that comes with a property called Value. The model implements INotifyPropertyChanged. Next, assume a view model that knows the model and offers itself a property Value to a imaginary view. This view model is implemented as follows:

View model code snippet

public int Value
{
    get {
        Model.Value;
    }
    set {
        if(value != Model.Value) {
            Model.Value = value;
            OnPropertyChanged();
        }
    }
}

I.e. the whole purpose of the view at this point is to directly pass a property of the model to the view.

The view model is registered to the model's PropertyChanged events. Every time Value of the model changes, the view model notices the change and triggers a PropertyChanged event itself so that a view that binds to the view model's property Value knows to update itself.

This leads to multiple PropertyChanged calls If one changes the model via the view model:

  1. Once in the code of the view model that listens to changes of the model after executing Model.Value = value;
  2. And again inside the setter of Value due to OnPropertyChanged();

The only solution that comes to my mind is to completly separate the view model from the model. This includes holding a complete clone of the model's data. This way I can avoid the first call of PropertyChanged. Because I'm able to compare the value of the view model with the value of the model I can distinguish between different sources of the change (i.e. view model changed model or model was changed by another source).

Note that the view model is far more complex. Merging the model with the view model is not a solution.

Upvotes: 0

Views: 164

Answers (2)

The viewmodel should be in charge of updating the view and updating the model.

You've essentially identified the reason why the model shouldn't implement INotifyPropertyChanged, and shouldn't do anything that requires it to. There isn't a clean, normal MVVM way to do what you're trying to do. That suggests that you're doing MVVM wrong. MVVM isn't holy writ, of course, but it does work well and what you're doing instead has already gotten you into trouble. You've created a problem you didn't need to create, and there are no good solutions to it. The answer isn't to choose the least-worst solution; it's to go back and eliminate the problem from the design.

This design is fundamentally ill-conceived and any attempt to salvage it by adding further complexity will be a mess. It was worth doing because you learned from it, but it's not worth investing any more time in.

The answer to your literal question, "how to implement a viewmodel [property] that wraps a model's property", is:

Just like you did it in your public int Value example, but without the model implementing INotifyPropertyChanged.

Upvotes: 2

Nkosi
Nkosi

Reputation: 247133

If the view model is already registered to the model's property changed and in turn raises its own property change then there is not a need for OnPropertyChanged() in the property of the view model.

Remove OnPropertyChanged()

ViewModel code would look like.

public int Value {
    get {
        return Model.Value;
    }
    set {
        if(value != Model.Value) {
            Model.Value = value;
        }
    }
}

Upvotes: -1

Related Questions