Home > Back-end >  MVVM Getting data from View Model into Model
MVVM Getting data from View Model into Model

Time:01-06

I am trying to use a MVVM pattern for that. I have a Model and a ViewModel, let's call them ModelA and ViewModelA:

ModelA

public ObservableCollection<RVTLinkWrapper> CollectRVTLinks()
{
    var revitLinkInstances = new FilteredElementCollector(Doc)
        .OfClass(typeof(RevitLinkInstance))
        .WhereElementIsNotElementType()
        .Cast<RevitLinkInstance>()
        .Select(x => new RVTLinkWrapper(x));

    return new ObservableCollection<RVTLinkWrapper>(revitLinkInstances);
}

ViewModelA

private ObservableCollection<RVTLinkWrapper> rvtLinks;

public ObservableCollection<RVTLinkWrapper> RVTLinks { get; set; }

public ViewModelA(ModelA model)
{
    Model = model;
    RVTLinks = Model.CollectRVTLinks();
}

ViewModelA constructor is calling CollectRVTLinks from model, creating RVTLinks. Is it ok for me to later get RVTLinks inside my Model A (having in my MVVM) and if yes, how to do it properly?

How should I interchange data between Model and ViewModel in this case?

CodePudding user response:

You have multiple options. I'm not completely sure what's you're intention based on the question, but here are some general ideas:

Options 1 - let the collection live inside the model

ModelA.cs

public ObservableCollection<RVTLinkWrapper> RVTLinks { get; } = new();

public void Add(RVTLinkWrapper item)
{
    RVTLinks.Add(item);
}

public void CollectRVTLinks()
{
    var revitLinkInstances = new FilteredElementCollector(Doc)
        .OfClass(typeof(RevitLinkInstance))
        .WhereElementIsNotElementType()
        .Cast<RevitLinkInstance>()
        .Select(x => new RVTLinkWrapper(x));

    RVTLinks.Clear();

    foreach(var item in revitLinkInstances)
    {
        RVTLinks.Add(item);
    }
}

ViewModelA.cs

public ViewModelA(ModelA model)
{
    Model = model;
    Model.CollectRVTLinks();
}

ViewA.xaml

< ... ItemsSource="{Binding Model.RVTLinks}"> ...

Later in the app

//add a new item
Model.AddRVTLink(rvtLink);
//reload collection
Model.CollectRVTLinks();

Options 2 - reload the collection on changes

ModelA.cs


public IEnumerable<RVTLinkWrapper> CollectRVTLinks()
{
    var revitLinkInstances = new FilteredElementCollector(Doc)
        .OfClass(typeof(RevitLinkInstance))
        .WhereElementIsNotElementType()
        .Cast<RevitLinkInstance>()
        .Select(x => new RVTLinkWrapper(x));

    return revitLinkInstances;
}

ViewModelA.cs

public ObservableCollection<RVTLinkWrapper> RVTLinks { get; } = new();

public ViewModelA(ModelA model)
{
    Model = model;

    var revitLinkInstances = Model.CollectRVTLinks();
    UpdateLinks(revitLinkInstances);
}

private void UpdateLinks(IEnumerable<RVTLinkWrapper> revitLinkInstances)
{
    RVTLinks.Clear();

    foreach(var item in revitLinkInstances)
    {
        RVTLinks.Add(item);
    }
}

ViewA.xaml

< ... ItemsSource="{Binding Model.RVTLinks}"> ...

Later in the app

//reload collection when something changes
var revitLinkInstances = Model.CollectRVTLinks();
UpdateLinks(revitLinkInstances);

CodePudding user response:

I'm not sure it's what you're asking for but here's some generic mvvm advice.

The way that code you posted works is a bad idea in my experience.

The view, view model and model should have the least concrete dependence between them as you can reasonably manage. The model is often from a rest based web service.

Other alternatives are available but Inrecommend automapper to transfer data out a model dto to viewmodel and back again.

Get a dto class, use automapper to copy it's data into a new viewmodel instance.

Want to commit changes? Use automapper to copy the viewmodel data into a new instance of a model dto. Pass the dto to the service updates database or whatever.

This reduces the responsibilities of your classes. The viewmodel is adapting data to the view. It doesn't need to "know" anything about your dto. The dto is purely a dto. Adapting logic goes into automapper configuration. If you need to tweak your vew and viewmodel then maybe it's only they change. If the model is shared by other apps and changes then you limit changes in your view and viewmodel.

Also though, if you're editing something then you're already set up to first deep clone your viewmodel using automapper to a new instance. You can bin that copy if it fails validation and your original data is still ok.

  • Related