Sandbox
Sandbox

Reputation: 8178

MVVM - what is the ideal way for usercontrols to talk to each other

I have a a user control which contains several 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.

Upvotes: 15

Views: 10431

Answers (9)

Reed Copsey
Reed Copsey

Reputation: 564781

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 Dependency 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.

Upvotes: 14

Ray Burns
Ray Burns

Reputation: 62929

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.

Upvotes: 8

Scott Whitlock
Scott Whitlock

Reputation: 13839

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.

Upvotes: 0

Brad Cunningham
Brad Cunningham

Reputation: 6501

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

Upvotes: 0

Guge
Guge

Reputation: 4599

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...."

Upvotes: 3

Massimiliano
Massimiliano

Reputation: 17000

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.

Upvotes: 0

Andrew
Andrew

Reputation: 27294

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.

Upvotes: 0

Ana Betts
Ana Betts

Reputation: 74692

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.

Upvotes: 1

PanJanek
PanJanek

Reputation: 6685

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

Upvotes: 1

Related Questions