OfficeRibbon - STARIONGROUP/COMET-IME-Community-Edition GitHub Wiki
The CDP4-COMET Office Addin is developed using the NetOffice .NET Wrapper Assemblies for accessing MS Office applications. The COMAddin class provides extension points to implement the IDTExtensibility2, Office.IRibbonExtensibility and Office.ICustomTaskPaneConsumer interfaces. The OfficeRibbon is customized using the Office.IRibbonExtensibility
interface. The Office.IRibbonExtensibility
interface loads the XML markup, either from an XML customization file or from XML markup embedded in the procedure, that customizes the Ribbon user interface.
Any useful Office addin needs to customize the Office Ribbon to add controls to the Ribbon to allow the user to interact with the Addin. Ribbon customization is performed by overriding the GetCustomUI
method of the COMAddin
base class and returining valid Ribbon XML. The GetCustomUI
method is defined by the IRibbonExtensibility
interface that is implemented by the COMAddin
class of NetOffice, in order to use it, it must be overridden in the concrete Addin class.
IMPORTANT: invalid Ribbon XML that is returned from the GetCustomUI method will result in the Ribbon customization to be ignored.
The contents of the Office Ribbon shall be delivered by the different CDP4-COMET Plugins (Modules) at Addin startup. The result of using a control on the Ribbon, clicking on a button, selecting an item from a combobox, shall be executed by the Plugin that delivered that specific control. This is enabled by the IFluentRibbonManager
interface and the FluentRibbonManager
implementation of that interface.
Read more about customizing the Ribbon here, here and here.
The IFluentRibbonManager
interface is used to orchestrate the content of the Ribbon and the interaction with the controls on the Ribbon. The Office Ribbon makes use of call backs that are declared in the Ribbon XML. The Addin class implements these call backs and redirects the execution of these callbacks to the IFluentRibbonManager
. Each CDP4-COMET plugin that needs to expose it's functionality to the Addin has a reference to the IFluentRibbonManager
, where the IFluentRibbonManager
registers so-called RibbonParts
. The different RibbonParts
provide the IFluentRibbonManager
with specific bits of Ribbon XML and contain the business logic associated with the execution of the interaction with the controls on the bit of Ribbon XML that they deliver to the IFluentRibbonManager
. The IFluentRibbonManager
interface derives from the IFluentRibbonCallback
interface, the abstract RibbonPart
base class implements the IFluentRibbonCallback
interface. This interface defines all the possible call backs that can be implemented as part of the Ribbon customization.
The IFluentRibbonManager
is defined as follows:
public interface IFluentRibbonManager : IFluentRibbonCallback
{
bool IsActive { get; set; }
void RegisterRibbonPart(RibbonPart ribbonPart);
string GetFluentXml();
}
The RegisterRibbonPart
method is used to register RibbonParts
of a Module with the IFluentRibbonManager
. The GetFluentXml
method returns the combined Ribbon XML of all RibbonParts
that have been registered. This combined Ribbon XML is used to create the custom CDP4-COMET Ribbon of the Addin. The IsActive
property is used to enable or disable the IFluentRibbonManager
. When the IFluentRibbonManager
is inactive, the business logic defined in the RibbonParts
is not executed.
The IFluentRibbonCallback
interface that defines the different Callback methods that can be invoked by Ribbon customization:
public interface IFluentRibbonCallback
{
void OnAction(string ribbonControlId, string ribbonControlTag = "");
string GetDescription(string ribbonControlId, string ribbonControlTag = "");
string GetKeytip(string ribbonControlId, string ribbonControlTag = "");
string GetScreentip(string ribbonControlId, string ribbonControlTag = "");
string GetContent(string ribbonControlId, string ribbonControlTag = "");
string GetLabel(string ribbonControlId, string ribbonControlTag = "");
string GetSize(string ribbonControlId, string ribbonControlTag = "");
string GetSupertip(string ribbonControlId, string ribbonControlTag = "");
Image GetImage(string ribbonControlId, string ribbonControlTag = "");
bool GetEnabled(string ribbonControlId, string ribbonControlTag = "");
bool GetPressed(string ribbonControlId, string ribbonControlTag = "");
bool GetVisible(string ribbonControlId, string ribbonControlTag = "");
bool GetShowImage(string ribbonControlId, string ribbonControlTag = "");
bool GetShowLabel(string ribbonControlId, string ribbonControlTag = "");
}
Each of these call-backs can be defined in the Ribbon XML. The Ribbon XML specifies for the different kinds of controls XML attributes that have as value the name of the call-back that shall be invoked when the callback attribute is defined.
IMPORTANT: CDP4-COMET RibbonParts shall always use as value the exact name of the method as defined by the
IFluentRibbonCallback
interface. example:<button id="someid" label="this is a button" onAction="OnAction"/>
With the exception of the onAction XML attribute, the call back methods allow to dynamically set the properties of the Ribbon controls through these call-backs. The property and the associated callback cannot be declared at the same time. The onAction XML attribute defines the action that needs to be executed when a control is clicked.
WARNING: The control property and associated call-back cannot be declared at the same time! Example of INVALID Ribbon XML
<button id="someid" label="this is a button" getLabel="GetLabel"/>
. The label property and getLabel call-back shall not be declared in the same control.
Each Module that needs to be integrated with an Office Addin, most likely putting controls on the Ribbon, need to implement at least one Ribbon Part. A concrete Ribbon Part shall derive from the abstract RibbonPart
base class. The abstract RibbonPart
base class implements the IFluentRibbonCallback
interface as virtual methods. A concrete Ribbon Part can override these methods when required. Concrete RibbonParts
shall be instantiated in the IModule
implementing class of each CDP4-COMET Plugin. The constructor of a RibbonPart
is defined as follows:
protected RibbonPart(int order, IPanelNavigationService panelNavigationService)
The int
order parameter specifies in what order the Ribbon XML of the RibbonPart
should be displayed on the Office Ribbon. The IPanelNavigationService
panelNavigationService parameter is used to inject the IPanelNavigationService
in order to support navigation to the different IPanelViewModel
using the void Open(IPanelViewModel viewModel, bool useRegionManager) method where the useRegionManager
should be set to false. The IRegionManager
does not exist in an Office Addin, therefore it cannot be used to select where to place the IPanelView
. Displaying a browser (IPanelViewModel and IPanelView combination) is handled by the Addin class, see below. The content (XML) of the Ribbon that is exposed by a particular RibbonPart
is declared in an embedded resource and loaded by the RibbonPart
(this is performed in the constructor of the abstract base class). The name of the embedded resource is specified in the overridden GetRibbonXmlResourceNane
method, a convention based location of both RibbonPart
and resource make sure the proper XML is loaded.
- The
RibbonParts
shall be placed in a folder called OfficeRibbon in the root of the Plugin project. - The namespace of the
RibbonPart
shall not include the name of the folder, it shall be the same as the name of the assembly. - The name of a
RibbonPart
shall be<name>RibbonPart
. - The XML of the
RibbonPart
shall be placed in the following folder Resources\RibbonXml in the root of the Plugin project. The build action shall be embedded resource. - The file name of the XML ribbon resource shall have as it's extention .xml
- The
GetRibbonXmlResourceNane
method shall be overriden and return the name of the XML resource, excluding the .xml extension
The IFluentRibbonManager
is declared in the CDP4Composition Assembly. The FluentRibbonManager
class implements the IFluentRibbonManager
interface and is injected by PRISM/MEF into the different CDP4-COMET Plugins (Modules) that need to provide any Ribbon customization. COMET Plugins always contain one Module class that implements IModule
, the Module class shall use constructor injection to set it's RibbonManager
property:
[ModuleExportName(typeof(SomeCDPModule), "Some CDP Module")]
public class SomeCDPModule : IModule
{
[ImportingConstructor]
public SomeCDPModule(IFluentRibbonManager ribbonManager)
{
this.RibbonManager = ribbonManager;
}
internal IFluentRibbonManager RibbonManager { get; private set; }
}
Office Addins support showing Custom Task Panes as docked panels, this is a feature of Microsoft Office. Custom Task Panes are implemented as Winforms. The CDP4-COMET is implemented as a WPF application, WPF UserControls can be hosted by WinForms The Addin project contains one Winforms UserControl called TaskPaneWpfHostControl
that is instantiated each time a CDP4-COMET browser (view) needs to be visualized. The Addin listens for NavigationPanelEvent
messages on the CDPMessageBus
, whenever one of these events is received, depending on the PanelStatus
the browser is either displayed or closed and disposed of. The RegionName
property is used to decide where the Custom Task Pane needs to be placed in the Office window. This can either be left, right or bottom. The Region
that is declared on the IPanelView
is used by the IPanelNavigationService
to send the correct NavigationPanelEvent
.
When a user closes a panel using panel's close button, the panel will actually only be hidden and not closed.
When this happens a HidePanelEvent
message is added to the CDPMessageBus
. A RibbonPart descendent can therefore decide to listen for this event and have its own implementation on what to do next: Do nothing, or for example dispose the IPanelView
and IPanelViewModel
'by hand'.
read more about docking WPF panels in Addins here.