Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Programmatic access to Ribbon controls in VSTO

Tags:

.net

vsto

I am writing C# with VSTO in Visual Studio 2008 in order to create an add-in for Office 2007.

After I have defined a custom ribbon tab using XML, how do I obtain references to the various controls in the Ribbon? I would like to be able to do things like programatically manipulate the content of an EditBox.

like image 423
mcoolbeth Avatar asked Mar 25 '10 17:03

mcoolbeth


People also ask

What is ribbon system in MS Word?

What is the ribbon? The ribbon is a command bar that organizes a program's features into a series of tabs at the top of the screen. Ribbon tabs are composed of groups of closely related commands, designed to help users quickly find desired commands. Each ribbon is a bar (line) across the page.

What is the design ribbon?

The 'Design' ribbon is used to develop and visualize a model by creating diagrams, matrices and lists of important aspects of the system.


1 Answers

Direct programmatic access to ribbon control properties through callbacks is not possible. However, Visual Studio has a visual ribbon designer that does allow direct access. I'll describe both topics below.

When using ribbon callbacks, project code cannot talk to the controls, it can only listen. It's a one-way street, and the code can only wait for IRibbonUI to send callback requests for whichever control function was triggered by the user.

The only way to change the properties of a control is to "reboot" it. The proper term for this is Invalidate. Either a single control or the entire programmer-defined custom ribbon may be invalidated. This is done with the following two methods:

Microsoft.Office.Core.IRibbonUI.Invalidate() 
Microsoft.Office.Core.IRibbonUI.InvalidateControl(String) '"SomeControlName"

The properties of the controls are set when they are first created, or when they are invalidated. Most properties can be set in the Ribbon.XML when they are first initialized. Likewise, most properties can be set when control invalidation is triggered.

And that's the trick. Well, actually it's the first of two tricks.

When a control or ribbon is invalidated, all of its callbacks are triggered simultaneously; those being onAction, getPressed, getImage, getLabel, etc, or specifically for this OP: it's getText that asks for the contents of a Microsoft.Office.Tools.Ribbon.RibbonEditBox control, or any of the other controls with textual contents.

And that's the second trick.

The class or module code must keep its own private variables to represent the current values of ribbon control properties. Then when control callbacks are triggered, IRibbonUI is essentially asking what the properties should be, and the code should reply back with the desired values.

Voilà!  That's the entire process in a nutshell.

However...as stated above, there's another way: the Ribbon Visual Designer (RVD), which uses Microsoft Visual Studio Tools for Office (VSTO) as a wrapper for everything to do with ribbons. In doing so, it provides the classic "point & doubleclick" technique of creating event handlers which every programmer is accustomed to. It works just like Windows Forms. Simply double-click any control in the RVD to be taken directly to that control's _Click event in the code. The RVD even adds additional functionality, such as the Ribbon_Close() event, which can be used for things like saving the current states of controls.

But there's an important point to make about the RVD: a ribbon will only appear if its RibbonType property is set for the application in which it's designed for, and some of the values are undocumented..!

The RibbonType values follow this general format: Microsoft.AppName.MainCommandBarName. The documented values are seen in the drop-down list of the RibbonType box of the Properties panel the RVD. Some of the values are:

Microsoft.Excel.Workbook
Microsoft.Word.Document
Microsoft.Outlook.Contact 
Microsoft.Outlook.Mail.Read

To have an RVD ribbon appear in any of these apps, one need only start the RVD, set the RibbonType property, add controls, and write code for the events. The RVD handles it all; it makes working with ribbons so much easier than Ribbon.XML.

But VSTO is only promoted to work with certain Microsoft Office apps, such as Excel, Word, Outlook, etc. I say "promoted" in reference to the "undocumented" part mentioned above. VSTO works with many, perhaps even all of the Microsoft Office apps. One need only know the main commandbar name.

Most programmers who've worked with Microsoft Office commandbars and ribbons over the years are probably aware that ribbons grew out of the commandbar system, and adopted some of the same terminology, methods, and values. And every commandbar has a Name. This can be seen right in Visual Studio if the commandbar area is right-clicked. There are commandbars for Debug, Build, Standard, and many other purposes. And all versions of Microsoft Office have the VBA editor, which still uses classic commandbars.

That Name property is the key to creating ribbons for any MSO application, not just the documented ones. The name is what links a ribbon to the window of the application. Most windows have a default commandbar that descended from the originals decades ago, in most cases not seen since Microsoft Office 2003. Well...maybe. I've only tested it with Access. I may take a whack at some of the other apps in the future.

I'll provide an example from a project I'm working on right now: a VSTO Add-In for Word that converted to a VSTO Add-In for Access (process described here). The project has an RVD, and the RibbonType property is set to Microsoft.Access.Database.

Note: The drop-down checklist for RibbonType can be tricky. It doesn't like undocumented values. If the keyboard focus tabs through that field and the value is undocumented, it will be deleted. To make it stick, focus must be "clicked-out" by clicking the mouse somewhere else. It may be possible to somehow re-code Me.RibbonType = "" in Ribbon.Designer.VB to some other syntax, but this may interfere with the normal operation of the designer, and I haven't experimented with it.

I discovered this detail buried in the original code created by the designer for a Visual Studio COM Shared Add-In:

'Set up a custom button on the "Standard" commandbar.
Try
    oStandardBar = oCommandBars("Standard")
Catch ex As Exception
    'Access names its main toolbar Database.
    oStandardBar = oCommandBars("Database")
End Try

And there it was. Most of the MSO apps have a default toolbar called Standard, but for Access it's Database. I'd been experimenting with various strings for my Access RVD, but none were working:

Microsoft.Access
Microsoft.Access.Application
Microsoft.Access.Application.ActiveWindow
Etc.

Then I had a sudden idea and remembered that bit of code from the Shared COM Add-in and tried these:

Microsoft.Access.Standard
Microsoft.Access.Database

And bingo..! My RVD ribbon magically appeared in Access when I pressed F5.

Sorry if this post got long-winded. I hope it may help others.

like image 100
spinjector Avatar answered Nov 12 '22 05:11

spinjector