VSTO Excel preserve Ribbon state - c#

I have simple VSTO Excel 2013 Application level Add-in with custom Ribbon, which includes toggle button and checkbox. If I open two files (workbooks) I can see that the Ribbons do not preserve their state across multiple windows, meaning if I click on checkbox or toggle button on Second workbook the same checkbox state is shown on a first workbook and vise versa. I found an article which describes a similar situation for outlook : https://www.add-in-express.com/creating-addins-blog/2013/01/30/preserve-outlook-ribbon-controls-state/ but unfortunately the Inspector window event is not available in Excel. Any idea on how to deal with it?

You need to use callbacks instead of attributes in the Ribbon XML. Also when a user changes the active window you need to call the Invalidate/InvalidateControl method of the IRibbonUI interface to force Office applications (Excel in your case) call your callbacks for the current state of controls. It's pretty easy...
You can read more about the Ribbon UI (aka Fluent 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)
Also you may find the following ones helpful:
Chapter 11: Creating Dynamic Ribbon Customizations (1 of 2)
Chapter 11: Creating Dynamic Ribbon Customizations (2 of 2)

I tried a sample with a toggle button with toggle on and then switched to another workbook the toggle button doesnt persist. But then if you stored the pressed value in a variable and return that on getPressed callback of a toggle button it worked.
Ribbon.xml
<?xml version="1.0" encoding="UTF-8"?>
<customUI onLoad="Ribbon_Load" xmlns="http://schemas.microsoft.com/office/2006/01/customui">
<ribbon>
<tabs>
<tab idMso="TabAddIns">
<group id="group1" label="group1">
<toggleButton id="toggleButton1" label="toggleButton1" size="large" getPressed="buttonPressed" onAction="buttonAction"/>
</group>
</tab>
</tabs>
</ribbon>
</customUI>
Ribbon.cs
private bool isButtonPressed = false;
public void buttonAction(Office.IRibbonControl control, bool isPressed)
{
isButtonPressed = isPressed;
}
public bool buttonPressed(Office.IRibbonControl control)
{
return isButtonPressed;
}

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.

Can I hide an icon on a Ribbon for particular users?

I want to show an icon on a Ribbon tab for particular users.
like...
If username ="Mike"
hide icon1
else
show icon1
Is there any way to get username who are using Excel workbook in C#?
I can set up password for this icon but if I can get username, it will be easier.
You can get the username from the WindowsIdentity:
if (System.Security.Principal.WindowsIdentity.GetCurrent().Name.Equals("username"))
{
button1.Visible = true;
}
else
{
button1.Visible = false;
}
The Application class from the Excel object model provides the UserName property. Moreover, you can't set the Visible property directly for Ribbon UI controls. You need to use callbacks (getVisible) and call the IRibbonUI.Invalidete or InvalidateControl methods to get your callbacks invoked. 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)

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)

How to intercept clicking of a built-in Office Ribbon control

I'm wondering if it's possible to detect when a user has clicked the Header/Footer button in Excel so I can show some custom header/footer related ribbon controls on my add-in's tab and hide them when the user is not in header/footer edit mode.
Is it possible to hijack this button click somehow? I've seen applications hijack the Excel Save before. I'm looking for similar behavior just with the header/footer button.
I'm using C#, Visual Studio 2012 and Excel 2010. I've created my custom ribbon using the Ribbon XML approach.
One way I've discovered that worked was to use the <commands> section in the Ribbon XML (which I didn't know existed.) Apparently this mechanism allows you to re-purpose actions intrinsic to Excel but beware that not all controls support re-purposing the onAction callback)
<?xml version="1.0" encoding="UTF-8"?>
<customUI onLoad="Ribbon_Load" xmlns="http://schemas.microsoft.com/office/2006/01/customui">
<commands>
<command idMso="HeaderFooterInsert" onAction="testHeaderFooter"/>
</commands>
<ribbon>
<tabs>...
along with the associated event handler:
public void testHeaderFooter(Office.IRibbonControl control, bool cancelDefault)
{
MessageBox.Show("Testing.");
cancelDefault = false;
}
This link was very helpful:
http://social.msdn.microsoft.com/Forums/office/en-US/e1a60d16-053e-4697-b17c-b22d602f0400/intercept-the-onaction-event-of-a-gallery-element-of-excel-2007-ui-ribbon?forum=vsto

Categories