MVVM, collections and ORM
I was trying to use MVVM design pattern with WPF and Entity Framework to create a simple application. All goes well and good if the classes are loosely coupled, but if I have sth. like two model classes : Customer and Address and a Customer has a collection of Addresses.
Now for those classes I need to create two VM classes - CustomerVM and AddressVM. CustomerVM should have ObservableCollection of AddressVM objects. Every change made to those VM classes(which includes all CRUD operations on both CustomerVM and AddressVM) needs to be reflected in the model classes - which is why I end up writing a looot of code that eg. subscribes to the changed event of ObservableCollection and if a new object is added then add a new object to the model ... and so on ...
What to do with this? Is this usual while using MVVM? Am I doing everything ok? How to cut down the amount of code needed for such a simple class hierarchy? Are there any frameworks that can create basic VM classes that "behave well" with other classes in hierarchy? What to do if class relationships get MORE complex?
OR TO PUT IT SIMPLE:
How to reflect changes done in vm collections in model collections :
CustomerVM1.AdressesVM.Add(new AddressVM{City="New York"})
should cause an equivalent of:
Customer1.Adresses.Add(new Address{City="New York"})
There's also the same problem the other way round - how to reflect changes done to collections in model to be included in the view model, but I'm more interested in the first one, because it has a more practical ap开发者_开发问答plication and vm objects can in most cases be simply recreated.
You might be interested in the BookLibrary sample application of the WPF Application Framework (WAF). It shows how to use the Entity Framework and MVVM together.
Short hint: It doesn't create a wrapper ViewModel for every Entity class. Instead, it creates the ViewModel classes for the Views.
You're running into exactly the same problem I ran into when trying to figure out how to keep an ObservableCollection
in my ViewModel sync'd with a plain-old-collection in my Model. An ObservableCollection
is wonderful because the View can bind to it and automatically change when the collection changes. Unfortunately you've just moved the problem of sync down one level.
One option is to use ObservableCollections everywhere, even in the Model. This isn't very clean architecture because MVVM isn't supposed to make any demands on the Model.
What I did to solve it was to introduce a Presenter, so my architecture looks like this:
View -> ViewModel <-> Presenter <-> Model
Also, I made my ViewModels dumb. Here's how a typical user action takes place from initiation to completion:
- User clicks the Add button
- ViewModel either raises an event that the Presenter subscribes to, or calls a method on the presenter, or just calls a callback that the Presenter provided to the ViewModel when the ViewModel was constructed. Essentially it delegates the action to the Presenter.
- The Presenter calls Add on the Model.
- The Model reacts to the Add call, updating all of it's relevant state, including the plain-old-collection.
- The presenter, having executed the action on the model, then reads the new state from the Model and writes the state into the ViewModel. Binding takes care of synchronizing the View.
So in your case, the Presenter could subscribe to a CollectionChanged
event on the ObservableCollection
in the ViewModel, and when it changes, it reacts to the event by calling Add on the Model. On the other hand, when the Presenter is processing some other user action that calls Add on the Model (it knows because it handles all interaction with the Model), then it knows that it has to propagate that change to the ObservableCollection
in the ViewModel.
In my code, I simplified the situation... after every user action is executed on the Model by the Presenter, I do a straight copy of all relevant state in the Model to the applicable place in the ViewModel. You're doing a little more work than you need to, but in a typical CRUD type of application, there's no noticeable performance issue. If I have a really big collection of objects, performance could be a problem, and there I drop down to a more fine-grained synchronization (updating only the changed entity), at the expense of more complicated logic.
精彩评论