WPF MVVM: ObservableValidator with Model in backing field

57 views Asked by At

My Code looks a bit like the following:

public class MyModel {

    public string MyProperty { get; set; }

}

public class MyViewModel: ObservableValidator {

    private mModelInstance;

    public MyViewModel(MyModel modelInstance){
        this.mModelInstance = modelInstance;
    }

    [MinLength(20)]
    public string MyProperty {
        get => mModelInstance.MyProperty;
        set => SetProperty(ref mModelInstance.MyProperty, value, validate = true); // This doesn't work because mModelInstance.MyProperty is a Property which cannot be passed as ref
    }
}

Now I see a few possible ways to do this, but am unsure which is best:

  1. Move Validation and PropertyChanged to Model and introduce a private backing field for MyProperty in MyModel. I then expose ModelInstance as a Property in ViewModel. This allows me to use SetProperty(ref mMyProperty, value, validate = true) in the MyModel.MyProperty setter.

  2. I can change MyModel.MyProperty to be a public field instead of a public property. However, this (from what I know) is a bad practice. Is this also bad in a POCO?

  3. Instead of one call to SetProperty, I can do the following in the MyViewModel.MyProperty setter:

set {
    mModelInstance.MyProperty = value;
    OnPropertyChanged();
    ValidateProperty(value);
}

This works and my Model is unchanged (i.e. still has public properties, not fields). It is the approach I would have chosen, but the fact that I have 3 separate statements instead of the one provided by MVVM-Toolkit made me hesitate a bit.

1

There are 1 answers

1
ASh On BEST ANSWER

In my experience view model defines its own backing fields and also public method (e.g. Save()) to commit changes to model:

with more than one property it is very easy to create invalid combination of their values, and there is no telling how well model can handle it.

public class MyViewModel: ObservableValidator {

    private mModelInstance;

    public MyViewModel(MyModel modelInstance){
        this.mModelInstance = modelInstance;
    }

    private string _myProperty;
    [MinLength(20)]
    public string MyProperty {
        get => _myProperty;
        set => SetProperty(ref _myProperty, value, validate = true);
    }

    public void Save() {
        mModelInstance.MyProperty = _myProperty;
    }
}