Today's Guest Writer: Savraj Dhanjal
Savraj is a Program Manager on the Office User Experience team focused on user interface extensibility for Office developers.
One of the key design features of RibbonX is the "pull" model, a model where Office asks add-in controls for their state. Though different than the "push" model of CommandBars, the pull model enables a number of scenarios for add-ins such as end-user customization, a separation between UI and core solution code, and better performance.
The model is straightforward--Office asks you for information about your controls--it "pulls" this information from your solution. Typically, Office asks for control properties that you did not declare up front in your customUI markup. Let's say you've got a button that should only be enabled when a certain condition is present. You write a function that returns true when your button is enabled. In your customUI markup, you associate this function with your button.
When Office first loads your button, and the button is on screen, Office calls back to your code to see if the button should be enabled. Office doesn't ask again, unless you indicate that your state has changed, by calling IRibbonUI.Invalidate, which invalidates all of your custom controls, or IRibbonUI.InvalidateControl, which invalidates a particular control. The function that Office calls is called a callback.
The interaction between Office and your add-in is best summarized in the following excerpt from a screenplay:
Add-in: Hi Excel! Here's some customUI markup.
<button id="ButtonOne" label="Hello World!"
Excel : Great, I've applied it to the Ribbon. By the way,
it looks like you have set a callback for the enabled
state of ButtonOne. I'll call back to your function,
enabledState, the first time your button is on screen.
Time passes, user clicks on custom tab
Excel : The user clicked on your tab, your button is appearing.
Calling enabledState, is ButtonOne enabled?
Excel : Ok great, I won't ask you again until your state changes.
*Time passes, user does something
Add-in: My state changed. I'm calling Invalidate.
Excel : Ok, calling enabledState, is ButtonOne enabled?
Excel : I won't ask you again until state changes.
Go to *, until user closes the app.
Ok, so that wasn't too exciting. But it's an illustration of how pull works. Add-ins can return just about all of the properties you can declare in markup, like the images, labels, descriptions, screentips, visibility, and enabled state of controls, through callbacks. For dynamic controls, like galleries and comboboxes, callbacks return the items that populate these controls.
The pull model affords several benefits for developers. The first is free end-user customization. If an end-user wants to promote a custom gallery to the quick access toolbar, she can. This behavior is completely transparent to the solution developer. Since code is never tied to the location of a control, callbacks for the state, label, or other properties still work even if the control is on the QAT. If your control was copied elsewhere in the world of CommandBars, you would have to write code to update the state of your control in both locations.
If you've ever developed a complex solution with a large amount of UI, you probably understand the benefit of keeping core application code and the UI separate -- the benefit is that the UI remains easy to change. Because of the "location agnostic" nature of the pull model, RibbonX developers get this benefit as well. You (or a UI designer) can rearrange your UI without ever touching your core application code.
We're also making add-ins more performant (in our own small way) with the pull model. In CommandBars, you could waste time updating controls that were not available or visible to the user. With RibbonX, if you tell us your state has changed, we only ask you for the new state of your controls if it is applicable -- that is, if your controls are visible to the user. If your controls are not on the screen (perhaps they're on a different tab) there's not reason to keep these hidden controls up to date.
As a final note, the RibbonX implementation of the pull model brings add-ins much closer to how the applications have always worked internally. It should be no surprise that the Office apps follow this very same design pattern: If something changes, the on-screen controls get updated. When the state changes in an add-in, or in the application, Office updates its UI to reflect the new state.
I'm sure some of you are wondering about the Hollywood-quality screenplay I'm writing regarding Office add-ins. Does anyone have any connections to get it submitted? A tentative title could be "Don't call us, we'll call you."