I found a solution to this design issue. Similarly to what happens with dependency properties, a custom control can also expose custom commands. Since commands exposed directly by a control (as opposed to commands exposed by a viewmodel) are UI-specific, it's most appropriate to use RoutedUiCommand rather than custom ICommand implementations. RoutedUiCommands can be exposed as static properties, quite like what happens with DependencyProperty. In my case, the gallery control exposes a static BringIntoView command as such:
public partial class DefectGallery {
// the control exposes the following commands:
public static readonly RoutedUiCommand BringIntoView = new RoutedUiCommand;
// the control exposes the following depdendency properties:
public static readonly DependencyProperty ScrollSpeedProperty = DependencyProperty.Register(...);
...
}
The command is bound to code-behind from the xaml file of the DefectGallery control:
<UserControl.CommandBindings>
<CommandBinding Command="{x:static local:DefectGallery.BringIntoView}" Executed="OnBringIntoViewExecuted"/>
</UserControl.CommandBindings>
Finally, some other control needs to trigger the BringIntoViewCommand. It could e.g. a WPF provided command source like a button. In my case, I have implemented the ICommandSource interface on the map control in order in order to allow specifying a custom command that is executed whenever an icon on the map is clicked. I can now use the map control (first snippet above) from xaml like this:
<MapControl
Command="{x:static local:DefectGallery.BringIntoView}"
CommandTarget="{Binding ElementName=defectGalleryInstance}"
/>
Thus effectively I can "call" a control from another control using just declarative xaml.
Now, this seems to be as basic a pattern as adding a dependency property, so I am just surprised I have not found guidelines on this. It seems natural to me that a control exposes properties as well as commands; I consider these two to be the "interface" of the UI control towards other UI components, whereas the View model bindings are the interface towards the application layer. Oh well, WPF lends itself to different usage approaches, you just have to find what works for you/your application.