Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to update MVVM nested ViewModels when Model changes and vice versa?

Tags:

c#

mvvm

I'm looking for some advice on how to solve a problem which is bugging us at the moment.

Let's say we have a couple of business objects (POCOs) like

public class UserGroup
{
    public virtual ICollection<Person> People { get; set; }
}

public class Person
{
    public virtual ICollection<Adress> Adresses { get; set; }
}

public class Adress
{
    public virtual string StreetName { get; set; }
}

This is a bit simplistic but I hope it's enough so that you get the idea. UserGroup has a collection of Person instances and each Person instance has a collection of Address instances.

The ViewModel for the UserGroup POCO could possibly look like this:

public class UserGroupViewModel
{
    private UserGroup userGroupModel;

    public UserGroup UserGroupModel
    {
        get { return this.userGroupModel; }

        set
        {
            this.userGroupModel = value;

            this.PeopleViewModelCollection =
                 new ObservableCollection<PeopleViewModel>();

            foreach (Person p in this.UserGroupModel.People)
            {
                var personViewModel = new PersonViewModel();


                personViewModel.PersonModel = p;

                this.PeopleViewModelCollection.Add(personViewModel);
            }
        }
    }

    public ObservableCollection<PersonViewModel> PersonViewModelCollection
    {
        get;
        set;
    }
}

Where as the ViewModel for the Person POCO could look like this:

public class PersonViewModel
{
    private Person personModel;

    public Person PersonModel
    {
        get { return this.personModel; }

        set
        {
            this.personModel = value;

            this.AddressViewModelCollection =
                 new ObservableCollection<AddressViewModel>();

            foreach (Address a in this.PersonModel.Adresses)
            {
                var addressViewModel = new AddressViewModel();


                addressViewModel.AddressModel = a;

                this.AdressViewModelCollection.Add(addressViewModel);
            }
        }
    }

    public ObservableCollection<AddressViewModel> AddressViewModelCollection
    {
        get;
        set;
    }
}

Again it is overly simplistic but what I want to show is that ViewModels have ObserableCollections of other ViewModels nested inside them.

The setter of the respective Model property, e.g. PersonViewModel.PersonModel does create ViewModels for all the adresses of the Person and adds them to the ObservableCollection<AdressViewModels> AdressViewModelCollection property of the PersonViewModel.

At this point we could use this code to display these ViewModels in a View. We can e.g. display the StreetName of a Person's Adress.

Now what should you do when you delete an Adress of a Person? Removing the AdressViewModel from the PersonViewModel.AdressViewModelCollection will update the GUI but it actually does not allow to update the underlying models.

Similar to that if you add another Adress to a Person Model the existing ViewModels are not going to reflect this change since the PersonViewModel.AdressViewModelCollection would only be rebuilt once the PersonViewModel.PersonModel property is set again.

Is it there a (preferably easy) way to achieve this two-way update between ViewModel and Model? Or maybe this is not advisable and it's better to handle this problem in a completely different way?

I'm keen to hear different opinions on this problem!

EDIT: I would like to state that our model classes are generated by the Entity Framework 4.0 and are POCOs (see example of business objects above). I'm not sure if that was clear enough in the question itself. We would like to expose navigational properties (e.g. Person.Addresses) as ICollection<T>.

like image 224
Timo Kosig Avatar asked Nov 14 '22 03:11

Timo Kosig


1 Answers

You could simplify things using dynamic proxies (e.g Castle.Proxy), take a look at this post for an idea how to accomplish this.

like image 144
Gregor Slavec Avatar answered Dec 15 '22 05:12

Gregor Slavec