I have a word add on project with two ribbon.xml files. What I need to do is change the current ribbon at run time.
the method DocumentBase.CreateRibbonExtensibilityObject() can use to do the job. But I cannot find way to trigger this method at run time.
when app starts this method triggers.
protected override Microsoft.Office.Core.IRibbonExtensibility reateRibbonExtensibilityObject()
{
if (condition == true)
{
return Ribbon1;
}
else
{
return Ribbon2;
}
}
I need to change the current ribbon of application at run time
This behavior is by design. The Ribbon XML used must be pre-defined when a project is loaded; it cannot be changed or created at run-time.
It's possible to dynamically display or enable controls using call-backs. Labels and images on controls can also be loaded dynamically. Lists and dynamic menus can be populated dynamically. Put all you could ever need in the Ribbon XML at design time then hide/disable what should not be available by default.
(Responding to follow-up in comments) Also by design, it's not possible to work with third-party Ribbon customizations. Too many developers were manipulating both built-in and third-party menus and toolbars - users thought the Office application was "buggy" because things were disappearing/changing. So the Ribbon UI only allows accessing third-party controls if those have been purposely "shared" (by using the idQ attribute).
Related
I have created a C# VSTO add-in with Visual Studio 2019 that receives commands from a socket connection and it can insert text, modify buttons only in my ribbon using office Interop.
I want to know two things.
How can I get the name of all the ribbons (Home, Insert, Design,
....) programmatically?
Initiate a mouse click (for example click Bold button in the Home tab) on any other ribbons than the one I created.
For the 2nd question, I want to use office add-in only, not by simulating keypress/mouse event.
How can I get the name of all the ribbons (Home, Insert, Design, ....) programmatically?
There is no trivial way for getting this job done. You can try using Accessibility API. Microsoft Active Accessibility is a Component Object Model (COM)-based technology that improves the way accessibility aids work with applications running on Microsoft Windows. It provides dynamic-link libraries that are incorporated into the operating system as well as a COM interface and API elements that provide reliable methods for exposing information about UI elements.
Initiate a mouse click (for example click Bold button in the Home tab) on any other ribbons than the one I created.
You can use the CommandBars.ExecuteMso method which executes the control identified by the idMso parameter. This method is useful in cases where there is no object model for a particular command. Works on controls that are built-in buttons, toggleButtons, and splitButtons. On failure, it returns E_InvalidArg for an invalid idMso, and E_Fail for controls that are not enabled or not visible.
Application.CommandBars.ExecuteMso("Copy")
Accessibility API (as Eugene mentioned) is pretty much the only way to drive Outlook Ribbon and its controls. Keep in mind that since Microsoft has never documented the controls and their ids, they are subject to change between the versions.
If using Redemption (I am its author) is an option, it exposes SafeExplorer and SafeInspector objects that expose the ribbon and its controls using Accessibility and low level Windows API.
Redemption.SafeExplorer sExplorer = new Redemption.SafeExplorer();
sExplorer.Item = OutlookApplication.ActiveExplorer;
foreach (var tab in sExplorer.Ribbon.Tabs)
{
MessageBox.Show(tab);
}
This seems to have been asked several times on here with no real answer:
Accessing Ribbon Controls Programatically in an XML Ribbon
Office Ribbon: How to access a control when the ribbon was created using XML
If a ribbon is created using ribbon xml, as far as I can tell, there is no programmatic exposure of the components defined in that xml. The only obvious limited way to change the state of these components is to use something like an onAction, getContent, getImage event, and the IRibbonControl element offers very little for manipulating the element in question (not to mention, most of those functions only run once, when first rendered).
So I'm trying to find a way to programmatically access those xml ribbon elements.
There is no way to programmatically access Ribbon elements when using Ribbon XML. If you want to change the state of the Ribbon controls - you need to use IRibbonUI.Invalidate() to force a new rendering of the layout (potentially using properties that trigger different behaviors at rendering time via callbacks). This can be a good thing as you have more control over when drawing occurs if you are changing multiple items' state.
See related SO post on updating Ribbon UI control state.
If you want programmatic access to Ribbon elements, you should use the Ribbon Designer. However, as stated on MSDN, the designer doesn't support all customizations. Some speculate that the designer just wraps the Ribbon XML up for you under the hood.
You just have to learn the callback mechanism utilized by the Ribbon XML - there is no control tree for you to gain access to.
How does one set a ribbon button in a Word add-in to be enabled when a document is loaded and disabled when no documents are loaded, just Like most of the built-in buttons?
Can one bind a global flag to the "Enabled" property of the button, or is it more complicated than that? I know I could create a timed loop that checks for changes in Application.Documents, but I'm looking for something "cleaner" if possible.
I've already looked at Disable Own Word 2007 Add-In If No Document Loaded and other related questions.
There are several ways to handle this.
first, you can create a publicly exposed function that returns true or false for the enabled state of your button (however you want to determine that), you then define your ribbon xml to point to that function for the Enabled property getter. If you're dealing with an IExtensibility based addin, then this is the way you'd have to go.
If you're dealing with VSTO, then define your ribbon button in the ribbon designer and make it DISABLED by default.
Then, during the STARTUP event, hook the WORD object, specifically the NEWDOCUMENT, DOCUMENTOPEN and WINDOWACTIVATE events.
In the event handler code for each of those events, enable or disable your buttons as applicable depending on which event fired and which document was activated at the time.
Use the DocumentChange event instead. Hook up will be something like this:
Globals.ThisAddIn.Application.DocumentChange += new EventHandler(OnDocumentChange);
And the Handler
void OnDocumentChange()
{
this.myButton.Enabled = wordApp.Documents.Count > 0;
}
Interesting, my VSTO Contrib project (http://vstocontrib.codeplex.com/documentation) has some features which make ribbon management simpler.
The cleanest way is to use my ribbon factory, but the project will need to be updated to disable buttons if there are no viewmodels to query for the status of the button. In fact it is a scenario I havent really covered.
You have 3 parts an add-in is interested in, the view (window), the context (the document) and the ribbon. VSTO Contrib means you get a view model per context, and it manages/abstracts the ribbon and view so it appears you have a ribbon per context, and it tells you the current active view (for multiple windows showing same document scenarios).
The missing part is if there is a ribbon, but no contexts and no viewmodels, it should invalidate that ribbon control and disable it. It should be a pretty simple change, email me if you are interested in giving VSTO Contrib's RibbonFactory a spin and I can make this change for you.
I am currently diving into VSTO add-in development and ribbon customization for Word 2010. This works fine, but has a drawback: The ribbon customization should take place for only certain documents, but the IRibbonExtensibility.GetCustomUI() method is obviously called on application startup before any document is loaded. How can I accomplish this requirement?
You're right that it's only called once. About your only choice (and what's worked for me reasonably well), is to define EVERYTHING in your ribbon up front, then set the VISIBLE property to false or true as applicable depending on what doc is loaded, or whatever else is happening in your addin.
#drventure is right, you have to define your ribbon up front, then show/hide different buttons on the ribbon.
What might help you though is some of the features in a project I have been working on, VSTO Contrib, it allows you to create a ViewModel, which will be created for each open document, and it will discover and wire up the ribbon xml by convention.
In your case this would mean you can bind the ribbon buttons visibility to a property on the viewmodel, and you don't have to worry about keeping the window/documents syncronised. Have a read of http://jake.ginnivan.net/vsto-contrib/ribbon-factory and see if it will help you solve your problem with a heap less code =)
Does anyone know how to modify the content of the Excel ribbon at runtime with VSTO 2005SE? Not only update labels or dynamic menus, but also add or remove buttons, tabs, groups, drop downs etc. At runtime means not only at my add-in startup, but also during work with Excel.
Irrespective of VS version, I don't think all that you want is actually possible with the current version of the RibbonX control*. Specifically, there's no functionality for adding and removing. You can control visibility, though, so you can put everything in by default and make it visible or otherwise as needed.
* which was 2007 at time of writing - Excel/Office 2010 may have changed things
I agree with Mike, working with the visibility callback on controls or groups is probably your best bet (that's what we are using).
The entire ribbon layout is loaded from an XML string. I don't know if it is possible to trigger a reload of the XML, which you could then customize to load different XML content.
If you use Visual Studio 2008, you have a great ribbon designer.
Do you want to have methods that is triggered by excel?