8

I try to deal with problem of passing value from one ViewModel to another. Here is an example.

We have Parent View and its corresponding ViewModel, in that View we select item and then we want to create new Child View (to edit details of selection) which instantiates its ViewModel in XAML. Problem occurs when I need to pass value to the Child ViewModel constructor (it is Id of data that has to be fetched from database). I assume Parent's ViewModel has to communicate with Child's ViewModel - but it cannot be done since Child's ViewModel is not instantiated until Child's View do that in XAML, so we cannot use Messenger (MVVM Light Toolkit) and just propagate that info from Parent's ModelView because Child's ModelView has not been able to subscribe (register to that type of messages).

I do not want to break MVVM pattern, and cannot find any good solution for that. I appreciate for all help I can get.

kkris1983
  • 471
  • 1
  • 7
  • 15
  • Are you using a view model locator? You mention that your VM isn't instantiated until the Child's View exists. You're setting the data context in code behind? Our parent VMs have a collection of VMs for the children. We use a very similar messenger to MVVM Light. – SQLMason Jun 18 '11 at 00:06
  • 2
    Oh, and you won't "break" MVVM, it's a guide not a religion. – SQLMason Jun 18 '11 at 00:08
  • No I did not know about view model locator - will check that out. Child's DataContext for its viewModel is set in XAML. In our solution Parent cannot have collection of VMs for the Children, it only can pass Id of data that has to be fetched from database in Child's VM. – kkris1983 Jun 18 '11 at 00:34
  • Use the ViewModel Locator, it is what you need. In it's simplest form, it's a static MainViewModel which is instantiated in the APP.XAML code behind. Doing this will allow you to bind correctly to your elements using the properties of the object in VS. The MainViewModel has all other view models / collection of models. For Example: Locator.Main.Parent.Child – SQLMason Jun 18 '11 at 16:31
  • Dan Andrews I appreciate for Your comments, I will check that Locator out now. Best regards – kkris1983 Jun 18 '11 at 19:15

2 Answers2

6

One of the main tenants of the MVVM pattern is that you should be able to execute your ViewModel code without a View, in order to unit test your View logic. In othe words, ideally you should be able to execute your application in a 'headless' mode.

In your example you state that the ParentView creates a ChildView which in turn creates a ChildViewModel (which you are struggling to connect up). Can this work in headless mode? It seems to me that you are relying on your View to perform this Parent-Child navigation.

If you flip it the other way, have ParentViewModel create ChildViewModel, you no longer have a problem with communication between ViewModels. The ParentView needs to 'watch' (i.e. property change) for the new ChildViewModel being creates, and constructs the ChildView accordingly.

In more detail:

  1. ParentView instantiates ParentVM
  2. User interacts in such a way that the child is required
  3. ParentVM creates a ChildVM, exposing it via a ChildVM property
  4. ParentView handles the resultant PropertyChanged event, creating a ChildView, setting its DataContext to ChildVM.
ColinE
  • 68,894
  • 15
  • 164
  • 232
  • Wherever I check MVVM pattern (in books) VM is instantiated in View e.g. resources. May be there is something I do not understand, could You correct me please ? – kkris1983 Jun 18 '11 at 08:36
  • According to one approach of MVVM design (in books) VM should know nothing about its View. So how to instantiate VM if not in View's XAML / code behind ? – kkris1983 Jun 18 '11 at 08:58
  • @kkris1983, that is a good question - it deserves its own page ;) – James L Jun 18 '11 at 12:12
  • 3
    @kkris1983 - it is a 'golden rule' of MVVM that the VM knows nothing of the View. Doing this would mean you could not run the VM without the View. Here's what I would do (1) ParentView instantiates ParentVM, (2) User interacts in such a way that the child is required, (3) ParentVM creates a ChildVM, exposing it via a ChildVM property, (4) ParentView handles the resultant PropertyChanged event, creating a ChildView, setting its DataContext to ChildVM. That should solve your problem! And it is totally 'valid' usage of MVVM. – ColinE Jun 18 '11 at 13:39
  • 1
    @ColinE I wouldn't do it that way. The viewmodel should be created first IMO. It's better to divorce the viewmodels from the views completely, and use some sort of discovery mechanism to find the correct view for a viewmodel. – James L Jun 18 '11 at 14:58
  • 2
    I prefer to keep thing simple. The question is coming from someone who is struggling with MVVM, I don't think adding in IOC or DI will help much. I have created numerous MVVM apps where the top-level view has created the top level view model, yet still been able to unit test the view model and have design time data. Having some third entity couple the view and view model is fine of course. But it is not necessary, and it is not part of MVVM itself. – ColinE Jun 18 '11 at 15:57
  • @Colin E can you please point out a link which would explain how to accomplish the 4th point which you have stated – KhannaB7 Dec 04 '15 at 08:38
0

What if any framework are you using? By that, I mean MvvmLight, Caliburn Micro, or Prism. Each framework has a messaging infrastructure. You can harness them to pass state back and forth using a publish/subscribe methodology. For example, take a look at Prism. There are several Quickstarts that show the eventing model. You can also maintain a view controller to orchestrate communication between views.

Take a look at Ward Bell's Prism Explorer sample app. This is an article from '09 however it's still relevant today. Especially see how he passes an entity object from a list view to a child detail view.

BenMorel
  • 34,448
  • 50
  • 182
  • 322
davidbitton
  • 818
  • 10
  • 20
  • I use MvvmLight and I know about messaging but the problem was that Parent's VM could not send message because child's VM may not be instantiated yet so it would not be able to register for that message – kkris1983 Jun 18 '11 at 08:36
  • While I am not familiar w. your architecture, you could have a controller that subscribes to the event, and then caches the results. The use that to instantiate views later on passing that to the new view in a state cache. – davidbitton Jun 20 '11 at 16:13