ViewModel to ViewModel Communication
Asked Answered
A

4

6

Given the following scenario:

  1. ViewModelA launches ViewModelB (via a common Controller, of course, that uses Ioc and DI to resolve the types needed).
  2. ViewModelB needs to set a property value in ViewModelA.

Is it bad to simply inject ViewModelA into ViewModelB via constructor injection and just set the property directly?

Or…

Should a messaging system like the EventAggregator from Prism be used to handle all communication between ViewModels?

I like the injection approach because it’s easy, but my instincts are telling me I’m missing something. I call on your collective wisdom to help fill in my blind spot.

Atombomb answered 26/1, 2011 at 16:31 Comment(0)
H
1

I suggest you read this question (and my answer) since it's similar, but not exactly your problem. It does deal with communication of properties between parent/child ViewModel objects.

Let's look at a basic example:

  • ViewModelA is the parent and has to present the Sum of some property on B
  • ViewModelB is the child and has a property that needs summing

So the user makes a request to edit the property on B and the request succeeds, so B presumably changes the value of its property and fires a PropertyChanged event.

ViewModelA could subscribe to the events on all children, but having gone down that path, I don't like it. When children are added and removed, you have a lot of bookkeeping to do.

Injecting A into B is cleaner, but you still have a lot of bookkeeping to do. What if you have a "Clear Children" action on A? You have to remember to properly get rid of the parent relationship from B to A in all cases. Still it's better than events in my opinion because it's more explicit.

Personally I like the messaging idea. I'm more familiar with MVVM Light's messenger than Prism, but it's the same idea... a global message bus. At any time, any B can say "I changed my property!" and then A listens for the notification and does the computation itself. I think this is your cleanest solution with much less bookkeeping.

Hymettus answered 26/1, 2011 at 17:48 Comment(2)
I ended up creating a MessagingService that wraps the Publish/Subscribe/Unsubscribe actions of the EventAggregator. The MessagingService gets injected into the ViewModelBase class I'm using so any ViewModel in my application can use it.Atombomb
@Chris Swain - I like it. That's the approach I would take in the future if I had to have ViewModel to ViewModel communication. However in my recent work, I've avoided all cases of this by forcing all communication through the Model. When anything changes in the Model, my Presenter knows about it and tells the top level ViewModel that something might have changed. It then passes a notification down the tree and all child, grandchild, etc., ViewModels check their model data to see if there is any change.Hymettus
B
2

I consider it a code smell if you need two-way references. Often you can replace one of the references with an event.

Let ViewModelB raise an event that ViewModelA subscribes to. A complete messaging system like the one found in Prism is certainly an option, but in your scenario it sounds like a 'normal' event will do just fine.

Bottrop answered 26/1, 2011 at 18:34 Comment(1)
I agree that, in the simplest scenario, the event option is the way to go. However, my application is quite large. So I ended up going with the messaging solution since messaging was inevitably going to be needed elsewhere throughout the application.Atombomb
H
1

I suggest you read this question (and my answer) since it's similar, but not exactly your problem. It does deal with communication of properties between parent/child ViewModel objects.

Let's look at a basic example:

  • ViewModelA is the parent and has to present the Sum of some property on B
  • ViewModelB is the child and has a property that needs summing

So the user makes a request to edit the property on B and the request succeeds, so B presumably changes the value of its property and fires a PropertyChanged event.

ViewModelA could subscribe to the events on all children, but having gone down that path, I don't like it. When children are added and removed, you have a lot of bookkeeping to do.

Injecting A into B is cleaner, but you still have a lot of bookkeeping to do. What if you have a "Clear Children" action on A? You have to remember to properly get rid of the parent relationship from B to A in all cases. Still it's better than events in my opinion because it's more explicit.

Personally I like the messaging idea. I'm more familiar with MVVM Light's messenger than Prism, but it's the same idea... a global message bus. At any time, any B can say "I changed my property!" and then A listens for the notification and does the computation itself. I think this is your cleanest solution with much less bookkeeping.

Hymettus answered 26/1, 2011 at 17:48 Comment(2)
I ended up creating a MessagingService that wraps the Publish/Subscribe/Unsubscribe actions of the EventAggregator. The MessagingService gets injected into the ViewModelBase class I'm using so any ViewModel in my application can use it.Atombomb
@Chris Swain - I like it. That's the approach I would take in the future if I had to have ViewModel to ViewModel communication. However in my recent work, I've avoided all cases of this by forcing all communication through the Model. When anything changes in the Model, my Presenter knows about it and tells the top level ViewModel that something might have changed. It then passes a notification down the tree and all child, grandchild, etc., ViewModels check their model data to see if there is any change.Hymettus
M
1

I suggest using a much lighter dedicated Messaging solution called "Light Message Bus". It is not part of any yet another ;-) MVVM framework, but independent component. And I got it working in no time in less than 3 minutes.

Marianelamariani answered 26/3, 2017 at 16:32 Comment(0)
O
0

You might find the sample applications of the WPF Application Framework (WAF) useful. The ViewModels don't know about each other. The mediation between them is done by Controllers. This way you can prevent cyclic dependencies between ViewModel objects.

Ostensive answered 29/1, 2011 at 19:24 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.