<?xml version="1.0" encoding="UTF-8" ?>
<?xml-stylesheet type="text/xsl" href="http://msmvps.com/utility/FeedStylesheets/rss.xsl" media="screen"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:wfw="http://wellformedweb.org/CommentAPI/"><channel><title>Excel Do, Dynamic Does : dynamic, Excel</title><link>http://msmvps.com/blogs/xldynamic/archive/tags/dynamic/Excel/default.aspx</link><description>Tags: dynamic, Excel</description><dc:language>en</dc:language><generator>CommunityServer 2008.5 SP2 (Build: 40407.4157)</generator><item><title>Who Says The Ribbon Is Hard?</title><link>http://msmvps.com/blogs/xldynamic/archive/2012/03/06/who-says-the-ribbon-is-hard.aspx</link><pubDate>Tue, 06 Mar 2012 20:41:00 GMT</pubDate><guid isPermaLink="false">d67277c4-116b-43f1-b688-e9ef184ea916:1807034</guid><dc:creator>Bob Phillips</dc:creator><slash:comments>8</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://msmvps.com/blogs/xldynamic/rsscomments.aspx?PostID=1807034</wfw:commentRss><comments>http://msmvps.com/blogs/xldynamic/archive/2012/03/06/who-says-the-ribbon-is-hard.aspx#comments</comments><description>
&lt;p&gt;


&lt;/p&gt;
&lt;h2&gt;Introduction&lt;/h2&gt;
&lt;p&gt;I was recently chatting with a friend, and he was asking how you can have dynamic ribbon buttons, buttons that are available depending upon worksheet events. I knocked up a simple example, and I thought I would share it here for anyone else who might be interested. It takes a few steps, but it is remarkably easy.&lt;/p&gt;
&lt;p&gt;The example has three buttons within a single group, on a custom tab. The first button can be hidden by changing a cell value (a data validation cell in this case), or have its visibility restored. The second does nothing, whilst the third can change the image when a certain cell is selected, from one image to another. This principle could easily be extended to have say different groups of buttons for each sheet in a workbook, hide/expose the group upon activation/deactivation of the sheet.&lt;/p&gt;
&lt;h2&gt;CustomUI Editor&lt;/h2&gt;
&lt;p&gt;If you want to look at the xml, you should download the &lt;a href="http://openxmldeveloper.org/blog/b/openxmldeveloper/archive/2009/08/07/7293.aspx"&gt;CustomUI Editor&lt;/a&gt;. It is hardly what you would call a sophisticated tool, but it does enable you to create xml for the ribbon customisations.&lt;/p&gt;
&lt;h2&gt;Coding Techniques&lt;/h2&gt;
&lt;p&gt;A couple of things about my code. I do not hardcode any values in the xml, apart from the ids of the code. Instead I use callbacks for all of the properties. As an example, I could setup a button in the xml like so&lt;/p&gt;
&lt;p&gt;&lt;span class="property"&gt;&amp;lt;button &lt;/span&gt;&lt;span class="propertyId"&gt;id&lt;/span&gt; &lt;span class="propertyValue"&gt;=&amp;quot;btnDynaRibbon1&amp;quot;&lt;/span&gt;&lt;br /&gt;&lt;span class="propertyId"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; label&lt;/span&gt; &lt;span class="propertyValue"&gt;=&amp;quot;Button 1&amp;quot;&lt;/span&gt;&lt;br /&gt;&lt;span class="propertyId"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; onAction&lt;/span&gt; &lt;span class="propertyValue"&gt;=&amp;quot;rxOnAction&amp;quot;&lt;/span&gt;&lt;br /&gt;&lt;span class="propertyId"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; image&lt;/span&gt; &lt;span class="propertyValue"&gt;=&amp;quot;ImportExcel&amp;quot;&lt;/span&gt;&lt;br /&gt;&lt;span class="propertyId"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; size&lt;/span&gt; &lt;span class="propertyValue"&gt;=&amp;quot;1&amp;quot;&lt;/span&gt;&lt;br /&gt;&lt;span class="propertyId"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; visible&lt;/span&gt; &lt;span class="propertyValue"&gt;=TRUE&lt;/span&gt;&lt;br /&gt;&lt;span class="propertyId"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; screentip&lt;/span&gt; &lt;span class="propertyValue"&gt;=&amp;quot;Button that toggles the image&amp;quot;&lt;/span&gt; &lt;span class="property"&gt;/&amp;gt;&amp;gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;which has all of the properties, except &lt;span class="propertyId"&gt;onAction&lt;/span&gt;, hard-coded. &lt;/p&gt;
&lt;p&gt;I could do it this way, but I don&amp;rsquo;t, instead my xml looks like this&lt;/p&gt;
&lt;p&gt;&lt;span class="property"&gt;&amp;lt;button &lt;/span&gt;&lt;span class="propertyId"&gt;id&lt;/span&gt; &lt;span class="propertyValue"&gt;=&amp;quot;btnDynaRibbon1&amp;quot;&lt;/span&gt;&lt;br /&gt;&lt;span class="propertyId"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; getLabel&lt;/span&gt; &lt;span class="propertyValue"&gt;=&amp;quot;rxGetLabel&amp;quot;&lt;/span&gt;&lt;br /&gt;&lt;span class="propertyId"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; onAction&lt;/span&gt; &lt;span class="propertyValue"&gt;=&amp;quot;rxOnAction&amp;quot;&lt;/span&gt;&lt;br /&gt;&lt;span class="propertyId"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; getImage&lt;/span&gt; &lt;span class="propertyValue"&gt;=&amp;quot;rxGetImage&amp;quot;&lt;/span&gt;&lt;br /&gt;&lt;span class="propertyId"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; getSize&lt;/span&gt; &lt;span class="propertyValue"&gt;=&amp;quot;rxGetImageSize&amp;quot;&lt;/span&gt;&lt;br /&gt;&lt;span class="propertyId"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; getVisible&lt;/span&gt; &lt;span class="propertyValue"&gt;=&amp;quot;getVisible&amp;quot;&lt;/span&gt;&lt;br /&gt;&lt;span class="propertyId"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; getScreentip&lt;/span&gt; &lt;span class="propertyValue"&gt;=&amp;quot;rxGetScreentip&amp;quot;&lt;/span&gt; &lt;span class="property"&gt;&amp;gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;where all of the properties are using callbacks, which means that the value gets set within the VBA code. This is the code for the &lt;span class="propertyId"&gt;rxGetLabel&lt;/span&gt; callback &lt;/p&gt;
&lt;h2&gt;Ribbon Code&lt;/h2&gt;
&lt;p&gt;&lt;span class="codekeyword"&gt;Public Function&lt;/span&gt; rxGetLabel(control &lt;span class="codekeyword"&gt;As&lt;/span&gt; IRibbonControl, &lt;span class="codekeyword"&gt;ByRef&lt;/span&gt; label)&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="codekeyword"&gt;Select Case&lt;/span&gt; control.Id&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="codekeyword"&gt;Case&lt;/span&gt; CONTROLID_TAB_DYNA:&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;label = LABEL_TAB_DYNA&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="codekeyword"&gt;Case&lt;/span&gt; CONTROLID_GRP_DYNA:&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;label = LABEL_GRP_DYNA&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="codekeyword"&gt;Case&lt;/span&gt; CONTROLID_BTN_DYNA_1:&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;label = LABEL_BTN_DYNA_1&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="codekeyword"&gt;Case&lt;/span&gt; CONTROLID_BTN_DYNA_2:&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;label = LABEL_BTN_DYNA_2&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="codekeyword"&gt;Case&lt;/span&gt; CONTROLID_BTN_DYNA_3:&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;label = LABEL_BTN_DYNA_3&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="codekeyword"&gt;End Select&lt;/span&gt;&lt;br /&gt;&lt;span class="codekeyword"&gt;End Function&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;It simply tests for the control&amp;rsquo;s id, and returns the caption for the label appropriately. All of the values tested for and the values returned are stored as constants in the VBA (they could just as easily be stored in a table on a worksheet). The values of all of those constants in the above code snippet are&lt;/p&gt;
&lt;p&gt;&lt;span class="codecomment"&gt;&amp;#39; CONTROLID_ constant values&lt;/span&gt;&lt;br /&gt;&lt;span class="codekeyword"&gt;Global Const&lt;/span&gt; CONTROLID_TAB_DYNA &lt;span class="codekeyword"&gt;As String&lt;/span&gt; = &amp;quot;tabDynaRibbon&amp;quot;&lt;br /&gt;&lt;span class="codekeyword"&gt;Global Const&lt;/span&gt; CONTROLID_GRP_DYNA &lt;span class="codekeyword"&gt;As String&lt;/span&gt; = &amp;quot;grpDynaRibbon&amp;quot;&lt;br /&gt;&lt;span class="codekeyword"&gt;Global Const&lt;/span&gt; CONTROLID_BTN_DYNA_1 &lt;span class="codekeyword"&gt;As String&lt;/span&gt; = &amp;quot;btnDynaRibbon1&amp;quot;&lt;br /&gt;&lt;span class="codekeyword"&gt;Global Const&lt;/span&gt; CONTROLID_BTN_DYNA_2 &lt;span class="codekeyword"&gt;As String&lt;/span&gt; = &amp;quot;btnDynaRibbon2&amp;quot;&lt;br /&gt;&lt;span class="codekeyword"&gt;Global Const&lt;/span&gt; CONTROLID_BTN_DYNA_3 &lt;span class="codekeyword"&gt;As String&lt;/span&gt; = &amp;quot;btnDynaRibbon3&amp;quot;&lt;/p&gt;
&lt;p&gt;&lt;span class="codecomment"&gt;&amp;#39; LABEL_ constant values&lt;/span&gt;&lt;br /&gt;&lt;span class="codekeyword"&gt;Global Const&lt;/span&gt; LABEL_TAB_DYNA As String = &amp;quot;Dyna-Ribbon&amp;quot;&lt;br /&gt;&lt;span class="codekeyword"&gt;Global Const&lt;/span&gt; LABEL_GRP_DYNA As String = &amp;quot;Dynamic Ribbon&amp;quot;&lt;br /&gt;&lt;span class="codekeyword"&gt;Global Const&lt;/span&gt; LABEL_BTN_DYNA_1 &lt;span class="codekeyword"&gt;As String&lt;/span&gt; = &amp;quot;Button 1&amp;quot;&lt;br /&gt;&lt;span class="codekeyword"&gt;Global Const&lt;/span&gt; LABEL_BTN_DYNA_2 &lt;span class="codekeyword"&gt;As String&lt;/span&gt; = &amp;quot;Button 2&amp;quot;&lt;br /&gt;&lt;span class="codekeyword"&gt;Global Const&lt;/span&gt; LABEL_BTN_DYNA_3 &lt;span class="codekeyword"&gt;As String&lt;/span&gt; = &amp;quot;Button 3&amp;quot;&lt;/p&gt;
&lt;h2&gt;Managing Changes&lt;/h2&gt;
&lt;p&gt;Taking one of the dynamic elements, the first button that can be made non-visible, the visible value is not a constant, but a variable as it has to be manipulated by the code&lt;/p&gt;
&lt;p&gt;&lt;span class="codecomment"&gt;&amp;#39; VISIBLE constant values&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span class="codekeyword"&gt;Global&lt;/span&gt; VISIBLE_BTN_DYNA_1 &lt;span class="codekeyword"&gt;As Boolean&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;This variable is initialised as TRUE in the Workbook_Open event, and in the callback procedure, the control&amp;rsquo;s visibility property is returned as whatever is in this variable&lt;/p&gt;
&lt;p&gt;&lt;span class="codekeyword"&gt;Public Function&lt;/span&gt; rxGetVisible(control &lt;span class="codekeyword"&gt;As&lt;/span&gt; IRibbonControl, &lt;span class="codekeyword"&gt;ByRef&lt;/span&gt; Visible)&lt;/p&gt;
&lt;p&gt;&lt;span class="codekeyword"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;Select Case&lt;/span&gt;control.Id&lt;/p&gt;
&lt;p&gt;&lt;span class="codekeyword"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Case&lt;/span&gt; CONTROLID_BTN_DYNA_1:&lt;span class="codekeyword"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;Visible = VISIBLE_BTN_DYNA_1&lt;/p&gt;
&lt;p&gt;etc.&lt;/p&gt;
&lt;p&gt;The visibility variable gets changed in simple worksheet event code (remember, I am using a data validation cell to drive this code).&lt;/p&gt;
&lt;p&gt;&lt;span class="codekeyword"&gt;Private Sub&lt;/span&gt; Worksheet_Change(ByVal Target As Range)&lt;/p&gt;
&lt;p&gt;&lt;span class="codekeyword"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Select Case&lt;/span&gt; Target.Address&lt;/p&gt;
&lt;p&gt;&lt;span class="codekeyword"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Case&lt;/span&gt; &amp;quot;$C$3&amp;quot;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;VISIBLE_BTN_DYNA_1 = Target.Value = &amp;quot;Visible&amp;quot;&lt;/p&gt;
&lt;p&gt;&lt;span class="codekeyword"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;End Select&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;mgrxIRibbonUI.Invalidate&lt;br /&gt;&lt;span class="codekeyword"&gt;End Sub&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;As you can see, it sets the variable depending upon the cell value. Finally, it invalidates the ribbon variable so as to rebuild our ribbon customisations. The ribbon variable gets set in the ribbon onLoad callback&lt;/p&gt;
&lt;p&gt;&lt;span class="codekeyword"&gt;Public Function&lt;/span&gt; rxDMRibbonOnLoad(ribbon &lt;span class="codekeyword"&gt;As&lt;/span&gt; IRibbonUI)&lt;/p&gt;
&lt;p&gt;&lt;span class="codekeyword"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Set&lt;/span&gt; mgrxIRibbonUI = ribbon&lt;br /&gt;&lt;span class="codekeyword"&gt;End Function&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;Invalidating the ribbon variable causes the callback routines to be re-entered; this is how you change things dynamically.&lt;/p&gt;
&lt;h2&gt;Summary&lt;/h2&gt;
&lt;p&gt;Hopefully you can see how simple it is to create dynamic ribbon customisations, and how to manage the changes within your VBA code. You should also be able to see how this can be extended to other areas of dynamic interaction.&lt;/p&gt;
&lt;p&gt;As I mentioned, I keep the CustomUI very simple, and rely on the VBA code to set all of the properties of my ribbon customisations. This is not necessary, it is a style aspect that I prefer, I like to the XML simple, reducing the amount of changes that I need to make there, and instead drive it all from VBA. I use a host of global constants for my ribbon values, but again as mentioned earlier, it would be just as simple (and maybe pro vide more manageability of the values) if all of the control properties were added as a table on a hidden worksheet, and grabbed from there on ribbon load.&lt;/p&gt;
&lt;p&gt;My example workbook is attached &lt;a href="http://tinyurl.com/7k7u2ck"&gt;&lt;img src="http://msmvps.com/resized-image.ashx/__size/550x0/__key/CommunityServer.Blogs.Components.WeblogFiles/xldynamic/0474.download.gif" border="0" alt="" /&gt;.&lt;/a&gt;&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://msmvps.com/aggbug.aspx?PostID=1807034" width="1" height="1"&gt;</description><category domain="http://msmvps.com/blogs/xldynamic/archive/tags/RibbonX/default.aspx">RibbonX</category><category domain="http://msmvps.com/blogs/xldynamic/archive/tags/Excel/default.aspx">Excel</category><category domain="http://msmvps.com/blogs/xldynamic/archive/tags/VBA/default.aspx">VBA</category><category domain="http://msmvps.com/blogs/xldynamic/archive/tags/dynamic/default.aspx">dynamic</category></item></channel></rss>