How to dynamically create Ribbon tabs?

I want to start developing a new application using PrismV4, MEF, Ribbon. But now I have a problem. How to dynamically create tabs for a ribbon? Each module in the application can create its own tab in the ribbon. And each tab can have many groups.

How can I do that? Where do I need to place the definitions of each group (which controls to use (buttons, text fields, drop-down lists, etc.) And the bindings of commands and how?

Do I need to write XAML somewhere in a module, or can all this be done with code? And the last question, how to notify Ribbon (in Shell) to add these tabs to Ribbon? Should I use EventAggregator to communicate from module to shell? Or?

+5
source share
3 answers

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):

// Deserialize UI controllers from configuration files
// Each controller should act as view-model for its UI elements

// Register controllers with UI Manager
foreach controller in config.UiControllers uiManager.AddController(controller);


void UiManager.AddController(UiController controller)
{
    // Load controller tool windows
    foreach toolWindow in contoller.toolWindows
    {
         toolWindow.LoadResources();
         toolWindow.DataContext = controller;
         mainWindow.AddToolWindow(toolWindow, contoller.PreferedUiRegion);
    }

    // Load controller toolbars
    foreach toolBar in controller.ToolBars
    {
         toolBar.DataContext = controller;
         mainWindow.AddToolBar(toolBar);
    }

    // Load controller contextual toolbar groups
    foreach group in controller.ContextualToolBarGroups
    {
         group.DataContext = controller;
         mainWindow.AddContextualToolBarGroupr(group);
    }

    // Load view models for specific model types
    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;

    // Enable activation of contextual tab group on activate of view (if user clicks on it)
    view.OnActivatedCommandParameter = viewModel.ContextualTabGroupName;

    // This command should ask mainWindow to find contextual tab group, by name, and activate it
    view.OnActivatedCommand = ModelActivatedCommand;

    mainWindow.DocumentArea.Content = view;
}
+2

, Region Adapter ( ( )

http://msdn.microsoft.com/en-us/library/dd458901.aspx

. ( , ).

IRibbonService, , , AddTab/AddGroup.

+2

: :

<!-- See code-behind for implementation of IRegionMemberLifetime interface. This interface
causes the RibbonTab to be unloaded from the Ribbon when we switch views. -->

<!--<ribbon:RibbonGroup Header="Group B1">
    <ribbon:RibbonButton LargeImageSource="Images\LargeIcon.png" Label="Button B1" />
    <ribbon:RibbonButton SmallImageSource="Images\SmallIcon.png" Label="Button B2" />
    <ribbon:RibbonButton SmallImageSource="Images\SmallIcon.png" Label="Button B3" />
    <ribbon:RibbonButton SmallImageSource="Images\SmallIcon.png" Label="Button B4" />
</ribbon:RibbonGroup>-->

CS:

using Microsoft.Practices.Prism.Regions;
//using Microsoft.Windows.Controls.Ribbon;

namespace Prism4Demo.ModuleB.Views
{
    /// <summary>
    /// Interaction logic for ModuleBRibbonTab.xaml
    /// </summary>
    public partial class ModuleBRibbonTab :  IRegionMemberLifetime
    {
        #region Constructor

        public ModuleBRibbonTab()
        {
            InitializeComponent();
        }

        #endregion

        #region IRegionMemberLifetime Members

        public bool KeepAlive
        {
            get { return false; }
        }

        #endregion
    }
}

:

public class ModuleC : IModule
    {
        #region IModule Members

        /// <summary>
        /// Initializes the module.
        /// </summary>
        public void Initialize()
        {
            /* We register always-available controls with the Prism Region Manager, and on-demand 
             * controls with the DI container. On-demand controls will be loaded when we invoke
             * IRegionManager.RequestNavigate() to load the controls. */

            // Register task button with Prism Region
            var regionManager = ServiceLocator.Current.GetInstance<IRegionManager>();
            regionManager.RegisterViewWithRegion("TaskButtonRegion", typeof(ModuleBTaskButton));

            /* View objects have to be registered with Unity using the overload shown below. By
             * default, Unity resolves view objects as type System.Object, which this overload 
             * maps to the correct view type. See "Developer Guide to Microsoft Prism" (Ver 4), 
             * p. 120. */

            // Register other view objects with DI Container (Unity)
            var container = ServiceLocator.Current.GetInstance<IUnityContainer>();
            container.RegisterType<Object, ModuleBRibbonTab>("ModuleBRibbonTab");
            container.RegisterType<Object, ModuleBNavigator>("ModuleBNavigator");
            container.RegisterType<Object, ModuleBWorkspace>("ModuleBWorkspace");
        }
+1

All Articles