VSTO Outlook Addin Ribbons not loading properly - c#

I'm currently reparing an Outlook VSTO Addin. The project contains 4 ribbons with their respective Ribbon Type:
CrmAppointmentRibbon.cs -> Type: Microsoft.Outlook.Appointment
CrmEmailNewRibbon.cs -> Type: Microsoft.Outlook.Mail.Compose
CrmEmailReadRibbon.cs -> Type: Microsoft.Outlook.Mail.Read
CrmEmailRibbon.cs -> Type: Microsoft.Outlook.Mail.Explorer
So when Outlook opens, the method ThisAddIn_Startup is called to initialize the Addin and I'm getting the ribbon collection as follows:
ThisRibbonCollection ribbonCollection = Globals.Ribbons[Globals.ThisAddIn.Application.ActiveInspector()];
So the ribbonCollection contains the 4 ribbons but there is a mismatch concerning the class type of the CrmEmailRibbon variable of the ribbonCollection. When I do
ribbonCollection.CrmEmailRibbon
It returns the CrmEmailReadRibbon instead of CrmEmailRibbon. So the CrmEmailReadRibbon is returned twice. It's the same ribbon returned from this two calls:
ribbonCollection.CrmEmailRibbon
ribbonCollection.CrmEmailReadRibbon
The first call should return its associated ribbon reference: CrmEmailRibbon.
Because of that I cannot access to the groups and buttons of the CrmEmailRibbon...
Did somebody encounter this behaviour ?

By running the following code:
ThisRibbonCollection ribbonCollection = Globals.Ribbons[Globals.ThisAddIn.Application.ActiveInspector()];
You get a ribbon instance for the inspector window which can be one of the following:
CrmAppointmentRibbon.cs -> Type: Microsoft.Outlook.Appointment
CrmEmailNewRibbon.cs -> Type: Microsoft.Outlook.Mail.Compose
CrmEmailReadRibbon.cs -> Type: Microsoft.Outlook.Mail.Read
To get the ribbon instance you need to pass an active explorer instance:
ThisRibbonCollection ribbonCollection = Globals.Ribbons[Globals.ThisAddIn.Application.ActiveExplorer()];
for the following instance:
CrmEmailRibbon.cs -> Type: Microsoft.Outlook.Mail.Explorer
Depending on the context you will get the appropriate ribbon instance.
But I'd suggest using ribbon callbacks instead of using the VSTO object model for dealing with the Ribbon UI (aka Ribbon UI). Moreover, VSTO doesn't provide all features of the Fluent UI. Sometimes you have to create a basic UI using the ribbon designer and then export it to a ribbon XML file where you could start using callbacks.
As my colleague stated, the Ribbon UI is a static thing from its birth. The only possible dynamism is callbacks and menu. So, you may compare both approaches:
Walkthrough: Create a custom tab by using the Ribbon Designer
Walkthrough: Create a custom tab by using Ribbon XML

Related

UI Ribbon: How to unpress a toggle button?

There are 4 toggle buttons, when I be click on one, the other 3 are not clicked
For example, when I click public, Confidential's Click will be removed. Only 1 can be selected.
<toggleButton id="textButtonpublic" getLabel="getpublic" getImage="getcolor" onAction="PublicAction" getVisible="getvisiblepublic" getPressed="GetPressedPublic" />
public void PublicAction(IRibbonControl control, bool pressed){
GetPressedConfidential();}
public bool GetPressedConfidential(IRibbonControl control)
{
return false;
}
It didn't work when I called the GetPressedConfidential method.
If the ribbon button comes from your add-in you need to use the Invalidate or InvalidateControl methods of the IRibbonUI interface that allows invalidating the cached value for a single control or all controls on the Ribbon user interface.
For example, if an add-in writer implements the getImage callback procedure for a button, the function is called once, the image loads, and then if the image needs to be updated, the cached image is used instead of recalling the procedure. This process remains in place for the control until the add-in signals that the cached values are invalid by using the InvalidateControl method, at which time, the callback procedure is again called and the return response is cached.
The getPressed callback has the following signature for the toggelButton control:
C#: bool GetPressed(IRibbonControl control)
VBA: Sub GetPressed(control As IRibbonControl, ByRef returnValue)
C++: HRESULT GetPressed([in] IRibbonControl *pControl, [out, retval] VARIANT_BOOL *pvarfPressed)
Visual Basic: Function GetPressed(control As IRibbonControl) As Boolean
The Fluent UI (aka Ribbon UI) is described in depth in the following articles:
Customizing the 2007 Office Fluent Ribbon for Developers (Part 1 of 3)
Customizing the 2007 Office Fluent Ribbon for Developers (Part 2 of 3)
Customizing the 2007 Office Fluent Ribbon for Developers (Part 3 of 3)

Adding to Ribbon at run time works once

Hi I'm trying to add the current open contacts phone numbers to a ribbon.
I have created the ribbon and added a SplitButton which will contain the phone numbers.
In 'ThisAddin' when the current explorer changes it triggers an event which simply gets the item type. If its a contact it calls
//ThisAddin.cs on explorer change event - if is contact run:
Globals.Ribbons.CallContact.AddButton(contactItem.BusinessTelephoneNumber);
//Ribbon class
internal void AddButton(string name)
{
if (name != null && name.Count() > 2)
{
RibbonButton item = Globals.Factory.GetRibbonFactory().CreateRibbonButton();
item.Label = name;
item.ShowLabel = true;
this.newSplit.Items.Add(item);
}
}
This works once, first time opening a contact the phone number is displayed in the ribbon. Opening another contact window will cause the ribbon items to be added but are blank and null.
I'm simply trying to add the contacts phone numbers to the ribbon and leave them there while the user can open another contact and the same code runs adding the phone numbers to the ribbon.
I don't need to keep reference to the items once they are added. Thank you for the help. I feel there needs to be an invoke in here somewhere.
You must tell Outlook to refresh the ribbon. See https://learn.microsoft.com/en-us/visualstudio/vsto/walkthrough-updating-the-controls-on-a-ribbon-at-run-time?view=vs-2019 for the sample code.
You will need to specify a callback to retrieve the button's caption instead of hard-coding it in the ribbon's XML.
Note that since you can have multiple inspectors open, you must provide data specific to each item opened in its own inspector.
The Ribbon UI is a static thing because it is loaded once at startup (or before the window is shown). The best what you can do is to define callbacks and get them called wherever you need. For example, you can define 'getVisible' callback for your ribbon controls instead of adding new elements at runtime.
The IRibbonUI.Invalidate method invalidates the cached values for all of the controls of the Ribbon user interface.
You can customize the Ribbon UI by using callback procedures in COM add-ins. For each of the callbacks that the add-in implements, the responses are cached.
For example, if an add-in writer implements the getImage callback procedure for a button, the function is called once, the image loads, and then if the image needs to be updated, the cached image is used instead of recalling the procedure. This process remains in place until the add-in signals that the cached values are invalid by using the Invalidate method, at which time, the callback procedure is again called and the return response is cached. The add-in can then force an immediate update of the UI by calling the Refresh method.
<customUI … OnLoad="MyAddinInitialize" …>
Dim MyRibbon As IRibbonUI
Sub MyAddInInitialize(Ribbon As IRibbonUI)
Set MyRibbon = Ribbon
End Sub
Sub myFunction()
MyRibbon.Invalidate() ' Invalidates the caches of all of this add-in's controls
End Sub
The Fluent UI is described in-depth in the following articles:
Customizing the 2007 Office Fluent Ribbon for Developers (Part 1 of 3)
Customizing the 2007 Office Fluent Ribbon for Developers (Part 2 of 3)
Customizing the 2007 Office Fluent Ribbon for Developers (Part 3 of 3)
Also, you may find the Walkthrough: Create a custom tab by using Ribbon XML helpful. Note, you can export an existing custom ribbon UI to the XML and continue dealing with a raw markup.

Load excel Ribbon on demand

I would like to add functionality to my Excel addin so I could load different Ribbons on demand.
At the moment I am trying by exporting the ribbon to XML and loading it
private Microsoft.Office.Core.IRibbonExtensibility ribbonObj;
protected override Microsoft.Office.Core.IRibbonExtensibility CreateRibbonExtensibilityObject()
{
DialogResult RibbonToLoad = MessageBox.Show("Yes = V2 No = V3", "Select Version", MessageBoxButtons.YesNo);
switch (RibbonToLoad)
{
case DialogResult.Yes:
ribbonObj = new RibbonV2();
return ribbonObj;
case DialogResult.No:
ribbonObj = new RibbonV3();
return ribbonObj;
}
return new RibbonV2();
}
The problema with this is I cannot find how to switch this Ribbon. I don't find it inside the Globals. object.
Also I tried without exporting to XML, but also I couldn't achieve the load on demand of a different ribbon while running(e.g. clicking a button on a WPF window...)
Any idea how to get this? I would like to have the possibility of loading different ribbons on the same addin(but only one would be present at once)
You can't manage the process of loading ribbon controls. But you can change visibility of your controls at runtime. The IRibbonUI interface provides the Invalidate and InvalidateControl methods that allow to trigger your callbacks where you can change visibility at runtime (getVisible).
In the following example, starting the host application triggers the onLoad event procedure that then calls a procedure which creates an object representing the Ribbon UI. Next, a callback procedure is defined that invalidates all of the controls on the UI and then refreshes the UI.
The following is the XML markup for Office to load the custom ribbon:
<customUI … onLoad=”MyAddInInitialize” …>
The following is the callback method for the onLoad event:
Dim MyRibbon As IRibbonUI
Sub MyAddInInitialize(Ribbon As IRibbonUI)
Set MyRibbon = Ribbon
End Sub
Sub myFunction()
‘ Invalidates the caches of all of this add-in’s controls
MyRibbon.Invalidate()
End Sub
You can read more about the Ribbon UI in the following series of articles in MSDN:
Customizing the 2007 Office Fluent Ribbon for Developers (Part 1 of 3)
Customizing the 2007 Office Fluent Ribbon for Developers (Part 2 of 3)
Customizing the 2007 Office Fluent Ribbon for Developers (Part 3 of 3)

Create parent menu in AddIn using c#

I want to add menu to visual studio in AddIn.
I found how to create submenu item in Expose an Add-In on the Tools Menu (Visual C#), but I want to create primary menu (like 'File', 'Edit', 'View' etc.)
How can I do that using c#?
I think You can use this:
Microsoft.VisualStudio.CommandBars.CommandBar menuBarCommandBar =
((Microsoft.VisualStudio.CommandBars.CommandBars)_applicationObject.CommandBars)["MenuBar"];
CommandBarPopup myNewPopUpControl =
menuBarCommandBar.Controls.Add(MsoControlType.msoControlPopup) as CommandBarPopup;
myNewPopUpControl.Caption = "MyMenu";
myNewPopUpControl.Visible = true;
First line is from the OnConnection of the Add-In template.
As I experienced each element of Controls collection has a zero Id, so the arrangment might be problematic. Also you can create Buttons and PopUps with Automation (Exception will be thrown otherwise)
http://msdn.microsoft.com/en-us/library/microsoft.visualstudio.commandbars.commandbarcontrols.add.aspx
http://msdn.microsoft.com/en-us/library/office/aa190793(v=office.10).aspx
Update:
Your question seems to be a duplicate
[a question] Adding a Menu to the Visual Studio Menu Bar within an Add-In [a]

c# Excel - Display ribbon on exit

I'm using VSTO to design an application with an Excel interface. I want to hide the ribbon on startup (shouldn't be needed in the application) and re-display it on exit (if the user had it originally displayed), to avoid irritating people who use the application and want a ribbon the next time they open Excel.
I can hide the ribbon using essentially the following code in ThisWorkbook_Startup (from this question Excel 2007 Minimize the Ribbon programatically but Not the menu bar):
Office.CommandBars cbs = null;
cbs = Application.CommandBars;
foreach (Office.CommandBar commandBar in cbs)
{
if (commandBar.Name == "Ribbon")
{
this.Application.ActiveWindow.Activate();
Application.SendKeys("^{F1}", true);
}
}
However, the same code or similar variations from the previously referenced question do not seem to work when placed in either the ThisWorkbook_Shutdown or ThisWorkbook_BeforeClose methods. The code is hit but never seems to execute - the ribbon is never restored.
Is there another way to restore the ribbon on exit?
Thanks,
Andrew

Categories