Adding buttons to the Word 2007 ribbon at runtime
The ribbon in Word 2007 is a great feature, and it can be customized fairly easily using Visual Studio or other tools. As far as I am aware though, it is impossible to add buttons at run time. This would be a great feature, one that is missed from the earlier versions of Word.
There is a way around it, although it doesn’t provide the same functionality of adding buttons at will. When a Word 2007 Add-In loads, if it has a custom ribbon, then the ribbons GetCustomUI method will be called. This by default returns a string, which is the XML defined in the Visual Studio designer. By modifying this method, extra buttons can be added, but be aware that this method is only ever called once, when the Add-In loads. Of course you could just define the buttons in the XML in the first place, but the method I outline here is good for a plug-in scenario, where you don’t know in advance what buttons might want to be added.
To cater for a plug-in scenario, you can define extra buttons in an external configuration file that is read at start up. This can then be parsed and added to the ribbons XML text in the GetCustomUI method. This can be used to add in any of the button styles available to the ribbon. You still need to implement handlers, which I will discuss in a later post. In this example, I will add a simple button that just uses the Microsoft happy face image.
First, I have defined a helper method which just returns a Stream from the resource file which contains the XML representation of the ribbon. The GetCustomUi method returns a string, and by default just calls the standard GetResourceText method which is created when you add a ribbon.
Stream ribbonStream = GetResourceStream("WordAddIn1.Ribbon1.xml");
I haven’t included the code for GetReourceStream method, it is straightforward and easy to create. Now, the Stream is loaded into an XmlDocument. This is because we are going to add a node later, so we need a read/write object.
XmlDocument ribbonDocument = new XmlDocument();
XmlNamespaceManager nsmgr = new XmlNamespaceManager(ribbonDocument.NameTable);
nsmgr.AddNamespace("r", "http://schemas.microsoft.com/office/2006/01/customui");
ribbonDocument.Load(ribbonStream);
Note the use of an XmlNamespaceManager. This is not strictly necessary in this example, but if you are going to work with Office open XML then you should get used to using this object. In the ribbon designer you need to define somewhere to place your custom buttons. For this example I have defined a group that I will add buttons to. This is defined in the XML like this:
<group id="grpCustomButtons"
label="Custom buttons" />
An XPath query will now be run nto get a reference to this XmlNode.
string xpath = "r:customUI/r:ribbon/r:tabs/r:tab[@idMso='TabAddIns']/r:group[@id='grpCustomButtons']";
XmlNode nodeCustomButtons = ribbonDocument.SelectSingleNode(xpath, nsmgr);
Now the custom buttons can be added to the nodeCustomButtons object. In this example I have just hard coded this, but ideally you would have helper methods that would look for a configuration file, load it and dynamically create the buttons from the information found there.
XmlNode nodeCustomButton = ribbonDocument.CreateElement("button",ribbonDocument.DocumentElement.NamespaceURI);
XmlAttribute att = ribbonDocument.CreateAttribute("id");
att.Value = "cb1";
nodeCustomButton.Attributes.Append(att);
att = ribbonDocument.CreateAttribute("label");
att.Value = "Custom button";
nodeCustomButton.Attributes.Append(att);
att = ribbonDocument.CreateAttribute("imageMso");
att.Value = "HappyFace";
nodeCustomButton.Attributes.Append(att);
att = ribbonDocument.CreateAttribute("size");
att.Value = "large";
nodeCustomButton.Attributes.Append(att);
This button will now be added to the nodeCustomButtons that was retrieved earlier.
nodeCustomButtons.AppendChild(nodeCustomButton);
And all that is left is to return the XML as a string as the method requires.
return ribbonDocument.OuterXml;

Figure 1 - The custom button displayed in thw Add-Ins tab
What comes next? This code only creates a custom button. It doesn’t create a handler for the button, so it is a useless button. What needs to be done next is to add a handler for this button. This code is based on a plug-in model, so this Add-In should also look in the configuration file for more information. Perhaps an assembly, and a class name and a method to call. The code above would be modified to add a handler, and the handler code created to allow for dynamic execution of code.
Wednesday, December 05, 2007 11:51:46 PM (AUS Eastern Daylight Time, UTC+11:00)
Word 2007