What if you had an aggregate Command object which specified the appropriate behaviour? I'm going to try to flesh your question out a little bit to specifics, correct me if I'm wrong:
Let's suppose that there are two relevant parts of your app - a map component, which can be zoomed and panned etc, and a set of controls, which present the user interface for zooming, panning and selecting between them - sort of a set of mode selectors. You don't want either of them to have a direct reference to the other, and the temptation is to have the map know directly about its set of controls, so that it can catch events from them and switch mode state appropriately.
One way to take care of this would be to have a set of CompositeCommands (available from the Prism Application Guidance) libraries inside an object injected into each of them. That way you get decoupling and a strong description of interface (you could also use events if you were that way inclined).
public class MapNavigationCommands{
public static CompositeCommand startPanning = new CompositeCommand();
public static CompositeCommand startZooming = new CompositeCommand();
public static CompositeCommand setViewbox = new CompositeCommand();
}
Your mode controls, up in the Ribbon, register with your DI framework to have that injected (not wanting to introduce DI into this example, I've just referenced these static members directly).
public class ModeControls : UserControl{
...
public void PanButtonSelected(object sender, RoutedEventArgs e){
MapNavigationCommands.StartPanning.Execute(this); //It doesn't really care who sent it, it's just good event practice to specify the event/command source.
}
}
Alternatively, in XAML:
...
<Button Command={x:Static yourXmlns:MapNavigationCommands.StartPanning}>Start</Button>
...
Now, over on the map side:
public class PannableMapViewModel{
public PannableMapViewModel(){
MapNavigationCommands.StartPanning.RegisterCommand(new DelegateCommand<object>(StartPanning));
MapNavigationCommands.SetViewbox.RegisterCommand(new DelegateCommand<Rectangle>(SetViewBox));
}
private void StartPanning(object sender){
this.SetMode(Mode.Pan); //Or as appropriate to your application. The View is bound to this mode state
}
private void SetViewbox(Rectangle newView){
//Apply appropriate transforms. The View is bound to your transform state.
}
}
Now you have a decoupled, strongly specified interface between two controls, maintaining ViewModel separation, which can be mocked out for your tests.