Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Initializing a viewmodel

Something that continues to confuse me about MVVM - if I use the view-first approach to constructing my objects (this appears to be the most common approach, at least after much reading and searching), how do I get contextual information into the viewmodel?

I've seen many answers to similar questions say "use the DI container to inject your model," but that doesn't help me here, so I'm going to provide a small example.

Let's say my application is a PeopleEditor. It's made to load and edit People objects, which are complex. When you load the application, you get a home screen that loads a bunch of People into memory - let's say that those are all made accessible via a collection that I can get to from my container. By clicking on a Person, you are taken to the editor screen. The editor is complex, so this is not a trivial master-detail view implemented in one screen.

So, on the home screen, when I click a person, the application needs to create a new view and viewmodel and show the view. If I create the viewmodel first, via the container or not, I can initialize it with the appropriate person object. This seems very natural to me, so I'm having a hard time figuring out why view-first seems to be the predominant pattern. How would I do this using the view-first approach? The view would create the viewmodel, which can get to the collection of People but doesn't know which person its editing. EDIT for clarity: Multiple People editors could exist at one time, each editing a different person.

The Prism 4.0 alpha's MVVM reference implementation uses a "state handler", which is basically a service that the app uses to store a constructor parameter in the container. It saves the state and calls ShowView, and the viewmodel that ultimately gets created imports a state object. This seems clunky to me - it's like it's trying to pretend it's loosely coupled when it's really not. Does anyone else have any other guidance?

like image 739
nlawalker Avatar asked Sep 01 '10 05:09

nlawalker


People also ask

How do you instantiate a ViewModel in Java?

To instantiate such basic viewmodel, create a ViewModelProvider with current activity/fragment reference and invoke get method with ViewModel's class.

How do I start a new activity from my ViewModel?

You should call startActivity from activity, not from viewmodel. If you want to open it from viewmodel, you need to create livedata in viewmodel with some navigation parameter and observe on livedata inside the activity.


1 Answers

nlawalker,

I'm not expert but what i learn about View-First and Model-First is:

  1. View-First: View programs ViewModel, You create view then viewmodel automatically created.
  2. Model-First: ViewModel programs View, You create ViewModel object graph in the root application, assign it to the root view data context. then lets the view render its related child depends on view model.

Don't mean to say Model-First approach is bad but, I prefer View-First approach because viewmodel can sits in code behind, so when some process require non-binding friendly task (PasswordBox, DialogConfirmation, ClosingForm etc), i can write my logic in code behind.

Anyway, To solve the case I usually used combination of IOC and Event Aggregator. Here it is:

  1. For viewmodel requires contextual information register its instance in IOC container either than its type. So it is alyas ready even its view not.
  2. When navigation action occur (by clicking on people list item) resolve your view with IOC container resolver. and send an event to navigation bus with specified parameter. Further this event will catch by target ViewModel and do something.

Registering instance of viewmodel is not really necessary. it is only to make sure that viewmodel is ready when event dispatched by the previous viewmodel.

UPDATE

but then to populate it with any kind of local context I need to use a global facility to send it an event?

In your case, contextual object isn't local it is rather a message passed between object invocation. Obviously in your model-first approach you do:

//selectedPeople is contextual object
myPeopleDetailVM.LoadData(selectedPeople)

it will pretty much the same when you pass selectedPeople to the argument of the event bus.

If you considering performance, than you can compare it with the WPF Routed Event System in this case Routing strategy is more complex than Event Bus and I think if you confident enough using WPF routed event than you should with Event Aggregator.

The only problem i see if you use built-in framework event aggregator (prism, mvvmlight), your viewmodel is polluted with event bus, if you complaining about this then i agree with you.

Hope that help.

like image 142
ktutnik Avatar answered Oct 24 '22 09:10

ktutnik