Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

MVVM with aggregated model classes - how to wrap in ViewModels?

Tags:

mvvm

wpf

I'm currently trying to create a small application using the MVVM pattern. However I don't really know how to correctly wrap up aggregated Model classes in my ViewModel. From what little I know about MVVM, you're not supposed to expose Models in your ViewModel as properties or else you could directly bind to the Model from your View. So it seems I have to wrap the nested Model in another ViewModel, but this imposes some problems while synching Model and ViewModel later on.

So how do you do that efficiently?

I'll give a short example. Let's suppose I have the following model classes:

public class Bar
{
    public string Name { get; set; }
}

public class Foo
{
    public Bar NestedBar { get; set; }
}

Now I create two ViewModel classes accordingly, wrapping the Models, but run into problems with the FooViewModel:

public class BarViewModel
{
    private Bar _bar;
    public string Name 
    { 
        get { return _bar.Name; }
        set { _bar.Name = value; }
    }
}

public class FooViewModel
{
    private Foo _foo;
    public BarViewModel Bar
    {
        get { return ???; }
        set { ??? = value; }
    }
}

Now what do I do with the Bar-property of FooViewModel? For "get" to work I need to return a BarViewModel instance. Do I create a new field of that type in FooViewModel and just wrap the _foo.NestedBar object in there? Changes to that field's properties should propagate down to the underlying Bar instance, right?

What if I need to assign another BarViewModel instance to that property, like so:

foo.Bar = new BarViewModel();

Now that won't propagate down to the model, which still holds the old instance of type Bar. I'd need to create a new Bar object based on the new BarViewModel and assing it to _foo, but how do you do that elegantly? It's pretty trivial in this sample, but if Bar is much more complex with lots of properties, that'll be a lot of typing... not to mention it'd be very prone to errors, if you forget to set one of the properties.

like image 591
Mario Avatar asked Dec 21 '22 23:12

Mario


1 Answers

@Goblin

There are some flaws with your code: e.g. what if I get a list of Foo objects from database and I want to wrap each of them in an ObservableCollection?

then your Constructor of FooViewModel should accept the Foo model as parameter and not create it inside the Constructor!

Normally you do this to wrap a model into a viewmodel and put it the same time into a bindable Collection:

IEnumerable<Foo> foos = fooRepository.GetFoos();
foos.Select( m => viewmodelCollection.Add(new ViewModel(m,e.g.Service)));

The models properties are not copied to the ViewModel hell no!!! The ViewModel does delegate its properties to the model properties like:

public class FooViewModel
{
   private Foo _foo;

   public FooViewModel(Foo foo,IService service)
   {
      _foo = foo;

   }

   public string FoosName
   { 
      get{return _foo.Name };
      set
      {
         if(_foo.Name == value)
            return;

         _foo.Name = value;
         this.NotifyPropertyChanged("FoosName");
      }
   }

}

And like Goblin said all UI-Specific interfaces like:

IDataErrorInfo
INotifyPropertyChanged
IEditableObject

etc...

are implemented the by the ViewModel ONLY.

like image 182
Elisabeth Avatar answered Jan 11 '23 04:01

Elisabeth