How to re-trigger GetCustomUI() from ExcelDNA - excel

I have, in ExcelDNA, created a custom ribbon (extending ExcelRibbon) and overridden the GetCustomUI() method to create a menu control from a list of strings. Basically:
public override string GetCustomUI(string RibbonID)
{
string customUIXml =
#"<customUI xmlns='http://schemas.microsoft.com/office/2006/01/customui' loadImage='LoadImage' onLoad='OnRibbonLoaded' >
<ribbon>
<tabs>
<tab id='CustomTab' label='My Dynamic Tab'>
<group id='SampleGroup' label='My Sample Group'>
<menu description='description' enabled='true' id='menuItem' visible='true' size='normal' >";
foreach (string itemName in _ItemNameList)
customUIXml += $"<button id='btn_tool_{itemName}' label='{itemName}' onAction='MyMethod' />";
customUIXml +=
#"</menu>
</group >
</tab>
</tabs>
</ribbon>
</customUI>";
return customUIXml;
}
Because _ItemNameList is retrieved from a different file/system, I can't place this customUI tag directly into the .dna file (as far as I know) and hence I build it on load via the GetCustomUI().
As a proof of concept, the onAction method will add a new item to _ItemNameList when the user clicks on a menu item.
But how do I get Excel to call GetCustomUI again in order to have the XML rebuilt?
I have tried invalidating the ribbon object itself, but this does not trigger Excel to call GetCustomUI again.
The next best thing I can think of (although I'm still to test this) is to create a menu with a whole load of invisible 'placeholder' buttons (by specifying the getVisible callbacks) and when the user clicks on a button, just invalidate the button that needs to now become visible, showing the new item added to _ItemNameList. I still need to think through how to get the correct button reference though... This also feels a little dirty.
Any ideas how to have Excel rebuild the ribbon?
Also open to other ideas to allow me to add items to a menu in an ExcelRibbon.

I think you are looking for the dynamicMenu control, which will trigger an event to let you dynamically set the contents of the menu, every time you click on it.
Something like this:
<?xml version="1.0" encoding="utf-8" ?>
<customUI xmlns="http://schemas.microsoft.com/office/2006/01/customui" onLoad="OnLoad">
<ribbon>
<tabs>
<tab id="MyAwesomeRibbon" label="My Awesome Ribbon">
<group id="MyDynamicGroup" label="Hello Dynamic!">
<dynamicMenu id="MyDynamicMenu"
label="Click for Awesome"
getContent="OnGetContent"
invalidateContentOnDrop="true"
size="large"
imageMso="HappyFace" />
</group>
</tab>
</tabs>
</ribbon>
</customUI>
Your OnGetContent method will get fired every time the user clicks on the ribbon button, so you can dynamically assemble the items.
e.g.
public string OnGetContent(IRibbonControl control)
{
var menuXml = #"
<menu xmlns='http://schemas.microsoft.com/office/2006/01/customui' itemSize='large'>
<button id='SaveButton'
label='Save'
onAction='OnSave'
imageMso='FileSave' />
<button id='AboutButton'
label='About...'
onAction='OnAbout'
imageMso='FileDocumentInspect' />
</menu>";
return menuXml;
}
Of course, you'd have to build this string dynamically from your list, etc.

Related

Getting a Dropdown to Work in a Customised Excel Ribbon

So I'm creating a custom Ribbon using the Office RibbonX Editor and Excel. I want to display a simple dropdown that allows the user to switch between three worksheets.
I'm not sure why it's going wrong, but I keep running into three errors that correspond to the onAction attribute for each item:
Ln 8, Col 51: The 'onAction' attribute is not declared.
Ln 9, Col 51: The 'onAction' attribute is not declared.
Ln 10, Col 51: The 'onAction' attribute is not declared.
Here is my code:
XML (customUI14.xml file):
<customUI xmlns="http://schemas.microsoft.com/office/2009/07/customui">
<ribbon>
<tabs>
<tab id="customTab" label="DropDown" insertAfterMso="TabHome">
<group id="customGroup" label="Custom Group">
<dropDown id="dropDown1" label="Dropdown Box">
<item id="dd01" label="Sheet1" imageMso = "_1" onAction="DDOnAction" />
<item id="dd02" label="Sheet2" imageMso = "_2" onAction="DDOnAction" />
<item id="dd03" label="Sheet3" imageMso = "_3" onAction="DDOnAction" />
</dropDown>
</group>
</tab>
</tabs>
</ribbon>
</customUI>
VBA:
Sub DDOnAction(control As IRibbonControl, id As String, index As Integer)
Select Case control.id
Case "dd01"
ActiveWorkbook.Sheets("Sheet1").Activate
Case "dd02"
ActiveWorkbook.Sheets("Sheet2").Activate
Case "dd03"
ActiveWorkbook.Sheets("Sheet3").Activate
End Select
End Sub
Hi the onAction attribute should placed in the dropdown and not in the item,
So the XML is :
<customUI xmlns="http://schemas.microsoft.com/office/2009/07/customui">
<ribbon>
<tabs>
<tab id="customTab" label="DropDown" insertAfterMso="TabHome">
<group id="customGroup" label="Custom Group">
<dropDown id="dropDown1" label="Dropdown Box" onAction="DDOnAction" >
<item id="dd01" label="Sheet1" imageMso = "_1" />
<item id="dd02" label="Sheet2" imageMso = "_2" />
<item id="dd03" label="Sheet3" imageMso = "_3" />
</dropDown>
</group>
</tab>
</tabs>
</ribbon>
</customUI>
and the code is like this
Sub DDOnAction(control As IRibbonControl, id As String, Index As Integer)
Select Case Index
Case 0
ActiveWorkbook.Sheets("Sheet1").Activate
Case 1
ActiveWorkbook.Sheets("Sheet2").Activate
Case 2
ActiveWorkbook.Sheets("Sheet3").Activate
End Select
End Sub

Excel VBA ribbon add-in as first tab

I made a custom ribbon addin following this article,
https://www.thespreadsheetguru.com/blog/step-by-step-instructions-create-first-excel-ribbon-vba-addin
It works perfectly but can I move the tab which I have made to be the second tab after the Start tab?
You can do what you wish to do but to do so will mean that you need to edit the CustomUI.Xml file which is located in the zip file that is an Office document.
If you are working in VBA then you will best be served by the CustomUI editor tool
https://github.com/OfficeDev/office-custom-ui-editor
This tool will extract the xml file from an Office document, allow you to edit and then save it back to the office document.
This is a good link to start reading up on Ribbon Xml.
https://www.rondebruin.nl/win/s2/win001.htm
The Xml below is from one of my CustomUI for Word. I think it does the same as you are asking in that I inserts the new tab to the left of the Past group on the Home Tab of the ribbon. It also replaces the Paragraph tab with a customised version.
<tab
idMso="TabHome">
<group
id = "Home.RegulatoryCMC"
label = "Regulatory CMC"
insertBeforeMso = "GroupClipboard"
visible="true">
<button
id = "Home.RegulatoryCMC.StartHere"
label = "Start Here"
onAction = "RibbonCallbacksForButtons.OnAction"
getSupertip = "RibbonCallbacksForSupertips.getSuperTip"/>
<button
id="Home.RegulatoryCMC.ShowStylePane"
label="Show Style Pane"
onAction="RibbonCallbacksForButtons.onAction"
getSupertip = "RibbonCallbacksForSupertips.getSuperTip"/>
<button
id="Home.RegulatoryCMC.ResetXML"
label="Reset XML"
onAction="RibbonCallbacksForButtons.onAction"
getSupertip = "RibbonCallbacksForSupertips.getSuperTip"/>
</group>
<group
idMso="GroupParagraph"
getVisible="RibbonCallbacksForVisibility.getVisible"/>
<box
id="Home.Paragraph.Status"
boxStyle="horizontal">
<buttonGroup
id="Home.Paragraph.Alignment">
<toggleButton idMso="AlignLeft"/>
<toggleButton idMso="AlignCenter"/>
<toggleButton idMso="AlignRight"/>
<toggleButton idMso="AlignJustify"/>
</buttonGroup>
<buttonGroup
id="Home.Paragraph.Marks"
visible="true">
<toggleButton idMso="ParagraphMarks"/>
</buttonGroup>
</box>
<box
id="ParagraphIndent"
boxStyle="horizontal">
<button idMso="IndentDecreaseWord"/>
<button idMso="IndentIncreaseWord"/>
</box>
<box
id = "ParagraphOther"
boxStyle="horizontal">
<gallery idMso="LineSpacingGallery"/>
<button idMso="SortDialogClassic"/>
</box>
<dialogBoxLauncher>
<button idMso="ParagraphDialog"/>
</dialogBoxLauncher>
</group>
</tab>

Ribbon XML: Custom Excel Tab Disappears with Addition of Menu

Heylo, I am having a rather frustrating issue with my custom Excel Tab. I currently have about 20 buttons that all do a variety of different things, and I would like to implement some menu's to declutter the tab a bit. I have an add-in with a bunch of macros and an embedded customUI.xml file to organize all of the buttons.
The problem is, whenever I try to add what I see as perfectly fine menu xml code to the customUI.xml file, and re-embed it in the add-in, the tab ceases to show up when I reload Excel. Before I put the menu in, the tab is there and everything is fine, but when I add the menu code, it just doesn't want to show up anymore. Below is an example of what I'm trying to do.
<customUI xmlns = "http://schemas.microsoft.com/office/2006/01/customui">
<ribbon>
<tabs>
<tab id = "MyTab" label = "My Tab">
<group id = "About" label = "About">
<button id = "Button1"
label = "About My Tab"
size = "large"
onAction = "AboutMyTab"
imageMso = "Help"
screentip = "About My Tab"
supertip = "Shows a dialog box that displays information about My Tab."
/>
</group>
<group id = "TestMenus" label = "My Test Menu">
<menu id = "MyMenu" label = "The Menu">
<button id = "ButtonX" label = "X" size = "large" imageMso = "FileSave" />
<button id = "ButtonY" label = "Y" size = "large" imageMso = "Bold" />
<button id = "ButtonZ" label = "Z" size = "large" imageMso = "Undo" />
</menu>
</group>
</tab>
</tabs>
</ribbon>
</customUI>
Whether I embed the menu in a group or not, it still causes the tab to not show up at all. Is it the schema I am using? I am confused on what I am doing wrong. Also, I am using Excel 2016 if that helps in any way.
Thank you for any help in advance.
You need to remove Size property from buttons in menu and add it to menu itself:
<menu id = "MyMenu" label = "The Menu" itemSize = "large">
<button id = "ButtonX" label = "X" imageMso = "FileSave" />
<button id = "ButtonY" label = "Y" imageMso = "Bold" />
<button id = "ButtonZ" label = "Z" imageMso = "Undo" />
</menu>

Dynamically changes ribbon's button label Excel

I am using the following piece of XML code to create a custom Ribbon for an Excel add-in.
<customUI xmlns="http://schemas.microsoft.com/office/2009/07/customui">
<ribbon startFromScratch="false">
<tabs>
<tab id="ComdinheiroTab" label="COMDINHEIRO">
<group id="ComdinheiroButtons" label="Comdinheiro">
<button id="Login" getLabel="getLabelLogin" image="Login" size="large" onAction="OnActionLogin"/>
</group>
</tab>
</tabs>
</ribbon>
</customUI>
I am using the following VBA code to set a label for the button login:
Sub getLabelLogin(control As IRibbonControl, ByRef returnedVal)
if loggedIn = true then
returnedVal = "Logged"
else
returnedVal = "Disconected"
end if
End Sub
The label's name changes successfully according to the variable loggedIn's value when the ribbon is loaded. However I wish I could change the label's values during the execution of my program. Is it possible to call getLabel event using a VB code? Is there anyway to refresh my ribbon so this event would be called again?
Yes, it's possible to run "get" callbacks later on. In order to do so, you need to create a module- or global-level variable to hold the "ribbon UI" object. That object has two useful methods: Invalidate and InvalidateControl. The first triggers all the "get" callbacks in the Ribbon XML. The second triggers the callbacks only for the specified control.
Your ribbon ui must be assigned to this object when the Ribbon loads. In order for this to happen, you need the attribute onLoadin the customUI tag of your Ribbon XML and its callback in your VBA.
<customUI xmlns="http://schemas.microsoft.com/office/2009/07/customui" onLoad="ribbonLoaded">
<ribbon startFromScratch="false">
<tabs>
<tab id="ComdinheiroTab" label="COMDINHEIRO">
<group id="ComdinheiroButtons" label="Comdinheiro">
<button id="Login" getLabel="getLabelLogin" image="Login" size="large" onAction="OnActionLogin"/>
</group>
</tab>
</tabs>
</ribbon>
</customUI>
In the VBA sample code, below, UpdateTheLabel is called from "the execution of my program" mentioned in the question. This procedure need not be connected to the RibbonXML in any way.
UpdateTheLabels action, however, is connected to the Ribbon: by calling InvalidateControl it causes a Ribbon control ("Login", in this case) to re-evaluate all its dynamic ("get") call-backs, such as getLabelLogin (which is in the Ribbon XML).
Dim ribbonUI as IRibbonUI
Sub ribbonLoaded(ribbon as IRibbonUI)
Set ribbonUI = ribbon
End Sub
Sub UpdateTheLabel
ribbonUI.InvalidateControl("Login")
End Sub
Sub getLabelLogin(control As IRibbonControl, ByRef returnedVal)
if loggedIn = true then
returnedVal = "Logged"
else
returnedVal = "Disconected"
end if
End Sub
It doesn't matter what procedure calls InvalidateControl as long as the procedure has access to the ribbonUI object.
More on this can be found in the MSDN article https://msdn.microsoft.com/en-us/library/aa338202(v=office.12)#OfficeCustomizingRibbonUIforDevelopers_Dynamically

How to define size of a button in Excel 2013 using customUI editor

I am trying to create a new ribbon with 2 buttons in Excel 2013. I was able to create it using Custom UI editor thanks to
Excel CustomUI ribbon layout and How to add a custom Ribbon tab using VBA?
When I input the code as
<button id="aa" label="CORE" onAction = "HMA_CORE"/>
it works but once I try this code
<button id="aa" label="CORE" size = "large" onAction = "HMA_CORE"/>
and then click validate in the customUI it says that "size attribute is not declared". I am not sure what to add. I saw http://www.rondebruin.nl/win/s2/win009.htm as well, but the code looks the same.
Any help will be appreciated.
Thanks
The code for the buttons looks like this
<customUI xmlns="http://schemas.microsoft.com/office/2006/01/customui">
<ribbon>
<tabs>
<tab id="toolRibbon" label="HMA-FUNCTIONS">
<group id="groupDocument" label="HMA-xml outputs">
<buttonGroup id="a">
<button id="aa" label="CORE" onAction = "HMA_CORE"/>
<button id="ab" label="PLANT" onAction = "HMA_PLANT"/>
</buttonGroup>
</group>
</tab>
</tabs>
</ribbon>
</customUI>
Give this a try using built in icons from Office (get rid of buttonGroup)
<customUI xmlns="http://schemas.microsoft.com/office/2006/01/customui">
<ribbon>
<tabs>
<tab id="toolRibbon" label="HMA-FUNCTIONS" insertBeforeMso="TabHome">
<group id="groupDocument" label="HMA-xml outputs">
<button id="aa" label="CORE" imageMso="MacroArguments" onAction = "HMA_CORE" size="large" />
<button id="ab" label="PLANT" imageMso="PictureBrightnessGallery" onAction = "HMA_PLANT" size="large" />
</group>
</tab>
</tabs>
</ribbon>
</customUI>
Reference: Office 2007 Icons Gallery
the problem was the space between the "size" and the "larger" statement! put it all together
error >> size = "larger"
correct >> size="larger"

Resources