C
C#2mo ago
Zoli

How to Properly Synchronize ViewModel and Model in MVVM (CommunityToolkit.Mvvm)

I'm working with an MVVM pattern using CommunityToolkit.Mvvm and have a FooModel and corresponding FooViewModel. When saving, I need to ensure that the ViewModel updates the Model correctly. I currently instantiate the model inside the ViewModel and update it when properties change. However, I'm unsure whether the model should be automatically updated as the ViewModel changes, or if I should create a new model object when saving?
public class FooModel
{
public int Property { get; set; }
public List<SubFooModel> SubFooModels { get; set; } = [];

public SubFooModel AddSubFoo()
{
var model = new SubFooModel();
SubFooModels.Add(model);
return subFooModel;
}
}

public class SubFooModel
{
public int Property { get; set; }
}

public partial class FooViewModel : ObservableObject
{
private readonly FooModel _model;

[ObservableProperty]
private int _property;

public ObservableCollection<SubFooViewModel> SubFooViewModels { get; private set; } = [];

partial void OnPropertyChanged(int value)
{
_model.FooProperty = value;
}

public FooViewModel()
{
_model = new FooModel();
Property = _model.FooProperty;
SubFooViewModels = new ObservableCollection<SubFooViewModel>(
_model.SubFooModels.Select(sub => new SubFooViewModel(sub))
);
}

[RelayCommand]
private void AddSubFoo()
{
var subFoo = _model.AddSubFoo();
SubFooViewModels.Add(new SubFooViewModel(subFoo));
}

[RelayCommand]
private void Save()
{
//Repo.Save(_model);
}
}

public partial class SubFooViewModel : ObservableObject
{
private readonly SubFooModel _model;

[ObservableProperty]
private int _property;

partial void OnPropertyChanged(int value)
{
_model.Property = value;
}

public SubFooViewModel(SubFooModel model)
{
_model = model;
Property = _model.Property;
}
}
public class FooModel
{
public int Property { get; set; }
public List<SubFooModel> SubFooModels { get; set; } = [];

public SubFooModel AddSubFoo()
{
var model = new SubFooModel();
SubFooModels.Add(model);
return subFooModel;
}
}

public class SubFooModel
{
public int Property { get; set; }
}

public partial class FooViewModel : ObservableObject
{
private readonly FooModel _model;

[ObservableProperty]
private int _property;

public ObservableCollection<SubFooViewModel> SubFooViewModels { get; private set; } = [];

partial void OnPropertyChanged(int value)
{
_model.FooProperty = value;
}

public FooViewModel()
{
_model = new FooModel();
Property = _model.FooProperty;
SubFooViewModels = new ObservableCollection<SubFooViewModel>(
_model.SubFooModels.Select(sub => new SubFooViewModel(sub))
);
}

[RelayCommand]
private void AddSubFoo()
{
var subFoo = _model.AddSubFoo();
SubFooViewModels.Add(new SubFooViewModel(subFoo));
}

[RelayCommand]
private void Save()
{
//Repo.Save(_model);
}
}

public partial class SubFooViewModel : ObservableObject
{
private readonly SubFooModel _model;

[ObservableProperty]
private int _property;

partial void OnPropertyChanged(int value)
{
_model.Property = value;
}

public SubFooViewModel(SubFooModel model)
{
_model = model;
Property = _model.Property;
}
}
5 Replies
Anton
Anton2mo ago
If you want other UI that depends on it to pick up the changes, you need it to be reactive. Otherwise, it doesn't matter when you create it. For all I care, you could create it when saving it
Zoli
ZoliOP2mo ago
In a reactive approach for an edit operation, FooModel is passed to FooViewModel via the constructor. However, this means that any modifications made in the ViewModel will be directly reflected in the original model, even if the user cancels the operation without saving. How can I ensure that changes are only applied to the original model after a successful save operation while still leveraging reactivity? What is the best practice for maintaining the original state if the user decides to discard the changes?
Anton
Anton2mo ago
I mean, just do the most logical thing Work with a copy on that page Apply it to the original model when you save Which is what what you're doing I think
Zoli
ZoliOP2mo ago
Yes, I cache the model when any changes happens automatically. One more thing if you dont mind, with the reactive approach I need to move more logic from viewmodels to models. In this case is model still okay to use as entity for crud operations on local db? Because I did not have any logic basically in my models previously, now I am moving all (at least what is really for the model) and it became kind of rich models and I was wondering can or is it still good practice to use that for crud operation with local db.
Anton
Anton2mo ago
I'd wrap them Like I'd have Model and like ObservableModel, or a separate model for the db But I wouldn't go for both they have different purposes you could try to configure like converters in EF core, but it might be harder than just a straight mapping + two separate classes also it's probably going to be easier if you don't encapsulate the data at the model level make an abstraction that has operations to update it in the more involved ways

Did you find this page helpful?