PowerPoint vba - Custom Ribbon/group does not refresh when screen is empty

394 Views Asked by At

I have three templates and for using these templates I am making an add-in with a custom Ribbon Tab. What I would like, is as follows: When PowerPoint is opened, and the add-in is loaded, the user only sees three buttons on the custom Tab (= the three templates) which can be used to start a new presentation. When template A is choosen to make a new presentation, group 1 gets visible on the custom Ribbon Tab. When the presentation is closed, the group disappears. And this also for 2 and 3. They are never visible all together.

I think I’m almost there, but the Ribbon does not refresh when there is no presentation already open (empty PPT screen) and I start a new one (or open one) via my menu. Then my template-depended group does not appear in the Ribbon.

XML:

<customUI onLoad="RibbonOnLoad"  …>

<group id="MyCustomGroup1" label="Name" getVisible="GetVisible" tag="MyPersonalGroup1"
And there I've added some custom buttons. 

I also made "MyPersonalGroup2" and "MypersonalGroup3" like this.

VBA what I have now

Dim Rib As IRibbonUI
Dim MyTag As String

'Callback for customUI.onLoad
Sub RibbonOnLoad(ribbon As IRibbonUI)
    Set Rib = ribbon
End Sub

Sub getVisible(control As IRibbonControl, ByRef returnedVal)
Select Case control.Tag
    Case "MyPersonalGroup1"
        returnedVal = ActiveWindow.Selection.SlideRange.Design.Name = ("TemplateA")
    Case "MyPersonalGroup2"
        returnedVal = ActiveWindow.Selection.SlideRange.Design.Name = ("TemplateB")
    Case "MyPersonalGroup3"
        returnedVal = ActiveWindow.Selection.SlideRange.Design.Name = ("TemplateC")
End Select
End Sub

Class module ApplicationEventClass:

Public WithEvents PPTEvent As Application

Private Sub PPTEvent_WindowSelectionChange(ByVal Sel As Selection)
    MyTag = Tag
    If Rib Is Nothing Then
        MsgBox "Error, restart your presentation"
    Else
        Rib.Invalidate
    End If
End Sub

I repeated this code for 'PPTEvent_AfterNewPresentation' 'PPTEvent_AfterPresentationOpen' 'PPTEvent_PresentationOpen' 'PPTEvent_PresentationClose' Is that necessary?

And this Module going with the code above:

Dim X As New ApplicationEventClass
Sub InitializePPTEvent()
Set X.PPTEvent = Application
End Sub

Many thanks for your help!

I posted this question about refresh with empty screen also on vbaexpress.com/forum/showthread.php?69782-PowerPoint-vba-Event-not-fired-when-screen-is-empty and https://learn.microsoft.com/en-us/answers/questions/796398/show-or-hide-custom-group-depending-on-powerpoint.html

2

There are 2 best solutions below

7
On

You need a sub that returns the visibilitiy per each group based on the current design:

Sub getVisible(control As IRibbonControl, ByRef returnedVal)
Select Case control.Tag
    Case "MyPersonalGroup1"
        returnedVal = ActiveWindow.Selection.SlideRange.Design.Name = ("TemplateA")
    Case "MyPersonalGroup2"
        returnedVal = ActiveWindow.Selection.SlideRange.Design.Name = ("TemplateB")
    Case "MyPersonalGroup3"
        returnedVal = ActiveWindow.Selection.SlideRange.Design.Name = ("TemplateC")
End Select
End Sub

And you have to call RefreshRibbon within a WindowSelectionChange-Event. Did you implement a Application-class already? It's described here: https://learn.microsoft.com/en-us/office/vba/powerpoint/how-to/use-events-with-the-application-object

0
On

The ribbon is static from its birth. The only possible dynamism is available through callbacks. In the ribbon XML you can define the getVisible callback which can be invoked when you need to hide or show controls.

For example, if a code writer implements the getVisible callback procedure for a button, the function is called once, the state loads, and then if the state needs to be updated, the cached state 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.

In the following example, starting the host application triggers the onLoad event procedure that then calls a procedure that creates an object representing the Ribbon UI.

<customUI … OnLoad="MyAddinInitialize" …>

Next, a callback procedure is defined that invalidates all of the controls on the UI and then refreshes the UI.

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 getVisible callback has the following signature:

C#: bool GetVisible(IRibbonControl control)

VBA: Sub GetVisible(control As IRibbonControl, ByRef visible)

C++: HRESULT GetVisible([in] IRibbonControl *pControl, [out, retval] VARIANT_BOOL *pvarfVisible)

Visual Basic: Function GetVisible(control As IRibbonControl) As Boolean

Read more about the Fluent UI (aka Ribbon UI) in the following series of articles:

If you develop a VSTO based add-in you may find the Walkthrough: Create a custom tab by using Ribbon XML article helpful.