tags:

views:

783

answers:

9

I have a a user control which contains sevral other user controls. I am using MVVM. Each user control has a corresponding VM. How do these user controls send information to each other. I want to avoid writing any code in the xaml code behind. Particularly I am interested in how the controls (inside the main user control) will talk to each other and how will they talk to the container user control.

EDIT: I know that using events-delegates will help me solve this issue. But, I want to avoid writing any code in xaml code-behind.

+1  A: 

I think the best solution would be using Publisher/Subscriber pattern. Each control registers some events and attaches delegetes to events exposed by other controls.

In order to expose events and attach to them you would need to use some kind of Mediator/EventBroker service. I found a good example here

PanJanek
Can you please explain this in detail? Do you mean using CLR delegate and events?
Sandbox
I've just edited my answer adding the link to presentation with example code from Marlon Grech's blog. View models communicate in publisher/subscriber pattern (no code behind is needed). The mediator service use CLR delegates for registering event handlers.
PanJanek
+1  A: 

The best way to do this in my opinion is via Commanding (Routed Commands / RelayCommand, etc).

I want to avoid writing any code in the xaml code behind.

While this is a laudable goal, you have to apply a bit of practicality to this, it shouldn't be applied 100% as a "thou shalt not" type of rule.

Paul Betts
http://codebetter.com/blogs/glenn.block/archive/2009/08/02/the-spirit-of-mvvm-viewmodel-it-s-not-a-code-counting-exercise.aspx
Jarrett Meyer
Great post, I'll have to read this!
Paul Betts
A: 

You can communicate between elements on the UI by using element binding, so assuming a user control you created exposes a property, the other user controls could bind to it. You can configure the binding, use dependency properties instead of basic properties / implement INotifyPropertyChanged but it is in theory possible, but does require some forethought to enable to communication this way.

You will probably find it far easier using a combination of events, code and properties than try a pure declarative way, but in theory possible.

Andrew
+12  A: 

Typically, it's best to try to reduce the amount of communication between parts, as each time two user controls "talk" to each other, you're introducing a dependency between them.

That being said, there are a couple of things to consider:

  • UserControls can always "talk" to their containing control via exposing properties and using DataBinding. This is very nice, since it preserves the MVVM style in all aspects.
  • The containing control can use properties to "link" two properties on two user controls together, again, preserving clean boundaries

If you do need to have more explicit communication, there are two main approachs.

  1. Implement a service common to both elements, and use Depedency Injection to provide the implementation at runtime. This lets the controls talk to the service, which can in turn, keep the controls synchronized, but also keeps the dependency to a minimum.
  2. Use some form of messaging to pass messages between controls. Many MVVM frameworks take this approach, as it decouples sending the message from receiving the message, again, keeping the dependencies to a minimum.
Reed Copsey
For point 2: Josh Smith's MvvmFoundation has a 'Messenger' class that uses a Register/Notify mechanism to pass messages across VMs. They are stored as Weak References to avoid memory leaks, and work really nicely!
IanR
Yeah, I would also recommend the `Messenger` class in MVVM Foundation. Great stuff.
Oskar
Yes - that's what I was thinking of when I mentioned the "Messaging to pass messages". It's an effective technique, if you don't want DI to inject services.
Reed Copsey
A: 

You can share some View Model objects between controls as well as Commands...

For example, you have some main control, which contains two other controls. And you have some filtering functionality in the main control, but you want to allow user to set some part of the filter in the first sub-control (like "Full filter") and some part of the filter in another (like "Quick filter"). Also you want to be able to start filtering from any of sub-controls. Then you could use code like this:

public class MainControlViewModel : ObservableObject
{
    public FirstControlViewModel firstControlViewModel;
    public SecondControlViewModel firstControlViewModel;

    public ICommand FilterCommand;
    public FilterSettings FilterSettings;

    public MainControlViewModel()
    {
        //...

        this.firstControlViewModel = new FirstControlViewModel(this.FilterSettings, this.FilterCommand);
        this.secondControlViewModel = new SecondControlViewModel(this.FilterSettings, this.FilterCommand);
    }
}

public class FirstControlViewModel : ObservableObject
{
    //...
}

public class SecondControlViewModel : ObservableObject
{
    //...
}

In the main control XAML you will bind sub-controls DataContext to the appropriate View Models. Whenever a sub-control changes filter setting or executes a command other sub-control will be notified.

Yacoder
+1  A: 

There are many differenct mechanisms for this, but you should first find out in what layer of your architecture this communication belongs.

One of the purposes of the MVVM framework is that different views can be made over the same viewmodel. Would those usercontrols talk to each other only in the view you are currently implementing, or would they have to talk to each other in other possible views? In the latter case, you want to implement it below the view level, either in the viewmodel or the model itself.

An example of the first case may be if your application is running on a very small display surface. Maybe your user controls have to compete for visual space. If the user clicks one usercontrol to maximize, the others must minimize. This would have nothing to do with the viewmodel, it's just an adaption to the technology.

Or maybe you have different viewmodels with different usercontrols, where things can happen without changing the model. An example of this could be navigation. You have a list of something, and a details pane with fields and command buttons that are connected to the selected item in the list. You may want to unit test the logic of which buttons are enabled for which items. The model isn't concerned with which item you're looking at, only when button commands are pressed, or fields are changed.

The need for this communication may even be in the model itself. Maybe you have denormalized data that are updated because other data are changed. Then the various viewmodels that are in action must change because of ripples of changes in the model.

So, to sum up: "It depends...."

Guge
A: 

As others have said you have a couple of options.

Exposing DepedencyProperties on your user controls and binding to those properties provides a pure XAML solution in most cases but can introduce some UI dependencies in order for the bindings to see each other

The other option is a decoupled messaging pattern to send messages between ViewModels. I would have your user controls bind to properties on thier own VM's and then on the property change inside that VM it can "publish" a message that notifies other "subscribers" that something has happened and they can react to that message however they want to.

I have a blog post on this very topic if it helps: http://www.bradcunningham.net/2009/11/decoupled-viewmodel-messaging-part-1.html

Foovanadil
A: 

If you're using strict MVVM, then the user-control is a View and should only "talk", or rather, bind, to its ViewModel. Since your ViewModels most likely already implement INotifyPropertyChanged, as long as they have a reference to each other, they can use the PropertyChanged events to be notified when properties change, or they can call methods (better if it's through an interface) to communicate with each other.

Scott Whitlock
so you mean if two user controls have to talk to each other, then they should do it via their respective VMs? and I don't think I quite agree to the point that they should subscribe to each other's PropertyChanged event.
Sandbox
@Sandbox: in the case where you're using true MVVM, then the View knows about its ViewModel, but Views shouldn't know about each other, so no, they should not talk directly to each other. You would be hard pressed to unit test the inter-View communication if you did it that way. And you can use whatever method you want for ViewModels to know about or communicate with each other. .NET is full of options. Use whatever fits the need.
Scott Whitlock
A: 

Your conceptual problem is here:

Each user control has a corresponding VM.

Having a separate ViewModel for every view pretty much defeats the concept of a ViewModel. ViewModels should not be one-to-one with views, otherwise they are nothing but glorified code-behind.

A ViewModel captures the concept of "current user interface state" -- such as what page you are on and whether or not you are editing -- as opposed to "current data values'.

To really reap the benefits of M-V-VM, determine the number of ViewModel classes used based on distinct items that need state. For example, if you have a list of items each of which can be displayed in 3 states, you need one VM per item. Contrarily, if you have three views all of which display data in 3 different ways depending on a common setting, the common setting should be captured in a single VM.

Once you have strucutred your ViewModels to reflect the requirements of the task at hand you generally find there is no need nor desire to communicate state between views. If there is such a need, the best thing to do is to re-evaluate your ViewModel design to see if a shared ViewModel could benefit from a small amount of additional state information.

There will be times when the complexity of the application dictates the use of several ViewModels for the same model object. In this case the ViewModels can keep references to a common state object.

Ray Burns