Ribbon XML: Custom Excel Tab Disappears with Addition of Menu - excel

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>

Related

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>

VBA - Trying to Input text and click Search button, All within a Table, within a Form, No ID Element, only Class Element

Trying to input a Value into an Input Box and press the Search button to get the results from a table.
I can't seem to figure out how to input the Value into the Box. The input box and button seems to be inside a form inside a table. No ID element.
**> Input Box has these properties**
<td Class = "searchRow">
<input type = "text" name = "name" value onblur = "Numberfield();" style = "width: 200px;" class = "required">
This is all inside Form ID "SearchForm" > div ID "Search" > Tr > Td CLass "searchRow"
After I grab the correct internet explorer tab, I need to getElementByClassName and inp9ut value
IE.Document.getElementsByTagName("tr").getElementsByTagName("input").Value = "Search"
IE.Document.getElementsByClassName("searchRow").getElementsByTagName("input").Value = "Search"
I can't seem to get any combination to work.
Another element is the Button.
Button has these properties
<td colspan = "6" style = "align:right;" class = "searchonly">
<input type = "button" class = "actionbutton" value = "search" onclick = "submitform()">
How do i Click this button that is in the Table Row.
IE.Document.getElementsByClassName("searchonly").getElementsByTagName("actionbutton").Click
Does this make sense?
Appreciate the help.
Better to add ID attribute and then use getElementsByID.
And If that is not possible then you can use XPATH and get the element by using following function.
function getElementByXpath(path) {
return document.evaluate(path, document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue;
}
console.log( getElementByXpath("VALUE OF XPATH") );
And you can easily get the XPATH by using the extension in any browser. Like XPath Finder available in google chrome.
I write the Answer as comments and code:
'What you want first
'**> Input Box has these properties**
'<td Class = "searchRow">
' <input type = "text" name = "name" value onblur = "Numberfield();" style = "width: 200px;" class = "required">
'This is all inside Form ID "SearchForm" > div ID "Search" > Tr > Td CLass "searchRow"
'What you try
'IE.Document.getElementsByTagName("tr").getElementsByTagName("input").Value = "Search"
'IE.Document.getElementsByClassName("searchRow").getElementsByTagName("input").Value = "Search"
'What should work
'Attention: the get methods work case sensitive. It's a difference between "Search" and "search"
'I write that because I wonder if the first letter of the ID "Search" is upper case in the original document
'
'You can seperate the div tag include all inner tags as own DOM object
Dim nodeDivSearch As Object
Set nodeDivSearch = IE.Document.getElementByID("Search")
'
'Now you can work on the new DOM object only
'Note that the getElements methods always create a NodeCollection
'All elements of the collection have an index. The first element always has
'index 0, so you can access the first input tag in the new DOM object as follows
'(getElementByID does not create a NodeCollection, because an ID should always
'be unique. So there is only one element for this criterion anyway)
nodeDivSearch.getElementsByTagName("input")(0).Value = "Search"
'
'I think your code will work with setting indexes
IE.Document.getElementsByClassName("searchRow")(0).getElementsByTagName("input")(0).Value = "Search"
'What you want second
'Button has these properties
'<td colspan = "6" style = "align:right;" class = "searchonly">
' <input type = "button" class = "actionbutton" value = "search" onclick = "submitform()">
'What you try:
'IE.Document.getElementsByClassName("searchonly").getElementsByTagName("actionbutton").Click
'I think you know what to do here
IE.Document.getElementsByClassName("searchonly")(0).getElementsByTagName("actionbutton")(0).Click
getElementsByClassName returns an array-like object of all child elements which have all of the given class names. So you need to choose which element you need using index in the returned array. So does it with getElementsByTagName.
So if the html code is like below:
<form id="SearchForm">
<div id="Search">
<table>
<tr>
<td Class="searchRow">
<input type="text" name="name" value onblur="Numberfield();" style="width: 200px;" class="required" id="a1">
</td>
<td colspan="6" style="align:right;" class="searchonly">
<input type="button" class="actionbutton" value="search" onclick="submitform()">
</td>
</tr>
</table>
</div>
</form>
Then the vba code to set value and click button should be like below:
IE.Document.getElementsByClassName("searchRow")(0).getElementsByTagName("input")(0).Value = "Search"
IE.Document.getElementsByClassName("searchonly")(0).getElementsByClassName("actionbutton")(0).Click
The code above is just for example, you should change the index according to the actual situation of the website you visit.

How to re-trigger GetCustomUI() from ExcelDNA

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.

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"

How can I databind the label of a WinJS.UI.AppBarCommand?

With Visual Studio 2012 I created a JavaScript Blank App, added a global variable in js/default.js:
var mylabel = "my label";
and I called
WinJS.Binding.processAll();
at the end of app.onactivated.
Then I added two AppBarCommands in default.html:
<button data-win-control="WinJS.UI.AppBarCommand"
data-win-bind="label: mylabel">
</button>
<button data-win-control="WinJS.UI.AppBarCommand"
data-win-bind="innerText: mylabel">
</button>
The first binding does nothing, the second one shows the text "my label" instead of the button. How can I databind the button label ?
You need to bind the label property of the app bar command control instance. This can be done with:
<button data-win-control="WinJS.UI.AppBarCommand"
data-win-bind="winControl.label: mylabel">
</button>
Found in the answer of another question that I can use:
data-win-options="{label: mylabel}"
But it doesn't work if I have a ListView with an itemtemplate that contains an AppBarCommand, and I want to databind to a List.

Resources