For non-contextual tabs, my favorite approach to this problem is to dynamically load components (for example, via reflection) that include XAML with binding to commands and virtual machines (or controllers) that include command implementations and execute these command bindings.
For contextual tabs, my favorite approach is to enable the Model to ViewModel mapping dictionary, then activate / deactivate contextual tabs by name that were loaded using the above approach (and pass them the correct data context) - view model).
The pseudocode should be more or less similar (depending on what your frameworks are implemented and what you should implement):
foreach controller in config.UiControllers uiManager.AddController(controller);
void UiManager.AddController(UiController controller)
{
foreach toolWindow in contoller.toolWindows
{
toolWindow.LoadResources();
toolWindow.DataContext = controller;
mainWindow.AddToolWindow(toolWindow, contoller.PreferedUiRegion);
}
foreach toolBar in controller.ToolBars
{
toolBar.DataContext = controller;
mainWindow.AddToolBar(toolBar);
}
foreach group in controller.ContextualToolBarGroups
{
group.DataContext = controller;
mainWindow.AddContextualToolBarGroupr(group);
}
foreach item in controller.ViewModelsDictionary
{
this.RegisterViewModelType(item.ModelType, item.ViewModelType, item.ViewType);
}
}
void UiManager.OnItemSelected(Object selectedItem)
{
var viewModelType = GetViewModelTypeFromDictionary(selectedItem);
var viewType = GetViewTypeFromDictionary(selectedItem) ?? typeof(ContentPresentor);
var viewModel = Reflect.CreateObject(viewModelType);
var view = Reflection.CreateObject(viewType);
viewModel.Model = selectItem;
view.DataContext = viewModel;
view.OnActivatedCommandParameter = viewModel.ContextualTabGroupName;
view.OnActivatedCommand = ModelActivatedCommand;
mainWindow.DocumentArea.Content = view;
}