none
Customizing the Explorer Ribbon for Different Group Folders RRS feed

  • Question

  • Hi

    I have an Outlook Add-in developed in VB6 which customizes the Outlook ribbon by adding a new tab and some buttons.

    At present I can customize the ribbon to show different buttons based on the active Explorer or Inspector using the following.

    Public Function IRibbonExtensibility_GetCustomUI(ByVal ribbonID As String) As String
        
        Select Case ribbonID
            Case "Microsoft.Outlook.Explorer"
                    IRibbonExtensibility_GetCustomUI = GetRibbonXML()
       
            Case "Microsoft.Outlook.Mail.Read"
                     IRibbonExtensibility_GetCustomUI = GetRibbonXMLRead()
       
            Case "Microsoft.Outlook.Contact"
                     IRibbonExtensibility_GetCustomUI = GetRibbonXMLContact()
           
            Case "Microsoft.Outlook.Mail.Compose", _
                    "Microsoft.Outlook.Task", _
                    "Microsoft.Outlook.Appointment", _
                    "Microsoft.Outlook.Contact"
                    IRibbonExtensibility_GetCustomUI = GetRibbonXMLDefault()
           
            Case Else
                    IRibbonExtensibility_GetCustomUI = GetRibbonXMLDefault()
       
        End Select

    End Function

    My problem is how do I customize the ribbon between different Explorer folder groups ie Mail, Contacts, Tasks, Notes?

    The above customized ribbon GetRibbonXML() as set for Microsoft.Outlook.Explorer is shown regardless of which folder I select in the navigation pane (even though Microsoft's built in tabs and controls change).

    Is there an event can I monitor to update the ribbon say when the Contacts folder is activated?

    Thanks in advance

    Friday, July 6, 2012 7:18 AM

Answers

  • When you get your event handler firing you can use the reference you have to the Ribbon and call its Invalidate() method to fire your getEnabled and getVisible callbacks to set what is enabled and visible from your UI.
     
    Those callbacks would look something like this in the ribbon XML:
     

    <button id="MyButton"

    size="large"

    getLabel="Ribbon_getLabel"

    onAction="Ribbon_onAction"

    getSupertip="Ribbon_getSuperTip"

    getImage="Ribbon_getImage"

    getVisible="Ribbon_getVisible"

    getEnabled="Ribbon_getEnabled" />


    --
    Ken Slovak
    [MVP-Outlook]
    http://www.slovaktech.com
    Author: Professional Programming Outlook 2007
    "Mike McGinty" <=?utf-8?B?TWlrZSBNY0dpbnR5?=> wrote in message news:b979934e-b7b4-41ec-a4d6-e065771a795a...

    Thanks Damian

    How do I call the function which checks the folder change selection event?

    Can you also post an example of the XML lines it would need to add

    I'm just learning how to do all this and in a state of overload at the moment. Gradually getting there though.


    Michael McGinty CY Innovations Pty Ltd


    Ken Slovak MVP - Outlook
    Friday, July 6, 2012 2:32 PM
    Moderator
  • Using "visible="true" is fixed and doesn't depend on a ribbon callback, just having the original ribbon XML requested.
     
    The getVisible() callback will be called both on the first use of that ribbon as well as when an invalidate action is called. If you have 2 controls and just use Invalidate() getVisible() would be called twice, and so on.
     
    What's not working if you use getVisible()? Is the callback called?

    --
    Ken Slovak
    [MVP-Outlook]
    http://www.slovaktech.com
    Author: Professional Programming Outlook 2007
    "Mike McGinty" <=?utf-8?B?TWlrZSBNY0dpbnR5?=> wrote in message news:0f067bd7-c24b-465c-baae-a496097b6e91...

    Thanks Ken

    If I use visible="True" instead of getVisible= the Explorer ribbon with the custom VBM tab and buttons loads correctly whenever Outlook starts

    I can now see how setting m_ribbon in the Ribbon_OnLoad callback works.

    I would need to make m_ribbon a global variable in order to use it to invoke InvalidateControl from  myOlExp_FolderSwitch() as it is located in a separate class module. Or else Dim and Set myOlExp plus relocate myOlExp_FolderSwitch() to the Add-in designer module where  IRibbonExtensibility_GetCustomUI () and the callbacks live

    Thanks for your help


    Michael McGinty CY Innovations Pty Ltd Publisher of Advantage VBM - Your Business Advantage


    Ken Slovak MVP - Outlook
    Wednesday, July 18, 2012 2:57 PM
    Moderator

All replies

  • Normally it is done be defining callbacks in ribbon xml that will instruct runtime when to show your buttons. Define callback for getEnabled or getVisible and attach to proper events in OOM to determine when it is time to re-evaluate if your buttons should be shown (selection change, folder selection change, etc.). Then call Invalidate/InvalidateControl on ribbon object that you created and outlook will call your callbacks again.

    Friday, July 6, 2012 7:32 AM
  • Thanks Damian

    How do I call the function which checks the folder change selection event?

    Can you also post an example of the XML lines it would need to add

    I'm just learning how to do all this and in a state of overload at the moment. Gradually getting there though.


    Michael McGinty CY Innovations Pty Ltd

    Friday, July 6, 2012 8:08 AM
  • When you get your event handler firing you can use the reference you have to the Ribbon and call its Invalidate() method to fire your getEnabled and getVisible callbacks to set what is enabled and visible from your UI.
     
    Those callbacks would look something like this in the ribbon XML:
     

    <button id="MyButton"

    size="large"

    getLabel="Ribbon_getLabel"

    onAction="Ribbon_onAction"

    getSupertip="Ribbon_getSuperTip"

    getImage="Ribbon_getImage"

    getVisible="Ribbon_getVisible"

    getEnabled="Ribbon_getEnabled" />


    --
    Ken Slovak
    [MVP-Outlook]
    http://www.slovaktech.com
    Author: Professional Programming Outlook 2007
    "Mike McGinty" <=?utf-8?B?TWlrZSBNY0dpbnR5?=> wrote in message news:b979934e-b7b4-41ec-a4d6-e065771a795a...

    Thanks Damian

    How do I call the function which checks the folder change selection event?

    Can you also post an example of the XML lines it would need to add

    I'm just learning how to do all this and in a state of overload at the moment. Gradually getting there though.


    Michael McGinty CY Innovations Pty Ltd


    Ken Slovak MVP - Outlook
    Friday, July 6, 2012 2:32 PM
    Moderator
  • I'm having trouble calling the InvalidateControl methods when the user selects another folder on the Outlook Explorer

    How/where do I instantiate m_Ribbon just for the Explorer ribbon and where should the following calls be located in the code?

    if ribbonID = "Microsoft.Outlook.Explorer" then

       m_Ribbon.InvalidateControl ("ButtonNewOl")
       m_Ribbon.InvalidateControl ("ButtonImportEmails")
       m_Ribbon.InvalidateControl ("ButtonImportAttachments")
       m_Ribbon.InvalidateControl ("separator1")
       m_Ribbon.InvalidateControl ("ButtonImportAppointments")
       m_Ribbon.InvalidateControl ("ButtonImportContacts")
       m_Ribbon.InvalidateControl ("ButtonImportTasks")
       m_Ribbon.InvalidateControl ("ButtonImportNotes")

    end if


    The following code is located in a class module and works correctly each time an new folder is selected on the Outlook explorer
    According to Microsoft this must be placed in a class module
    Public WithEvents myOlExp As outlook.Explorer

    Private Sub myOlExp_FolderSwitch()


        gsOLFolderName = myOlExp.CurrentFolder.Name

     
    End Sub

    The following code is located in a designer module. All ribbons correctly load depending on the type of inspector
    Implements IRibbonExtensibility

    Public Function IRibbonExtensibility_GetCustomUI(ByVal ribbonID As String) As String

        Select Case ribbonID
       
            Case "Microsoft.Outlook.Explorer"
       
                IRibbonExtensibility_GetCustomUI = GetRibbonXMLExplorer()
       
            Case "Microsoft.Outlook.Mail.Read"
       
                IRibbonExtensibility_GetCustomUI = GetRibbonXMLRead()
       
            Case "Microsoft.Outlook.Contact"
       
                IRibbonExtensibility_GetCustomUI = GetRibbonXMLContact()
           
            Case "Microsoft.Outlook.Appointment"
       
                IRibbonExtensibility_GetCustomUI = GetRibbonXMLAppointment()
           
            Case "Microsoft.Outlook.Task"
       
                IRibbonExtensibility_GetCustomUI = GetRibbonXMLTask()
           
            Case Else
       
                IRibbonExtensibility_GetCustomUI = GetRibbonXMLDefault()
       
        End Select

    End Function

    Private sub GetRibbonXMLExplorer ()
       
    "<mso:customUI xmlns:mso=""http://schemas.microsoft.com/office/2006/01/customui"" onLoad=""Ribbon_OnLoad"" >" & _
    "<mso:ribbon>" & _
    "<mso:tabs>" & _
    "<mso:tab id=""CustomTab"" label=""VBM"" insertAfterMso=""TabHome"" >" & _
    "<mso:group id=""RunVBM"" >" & _
    "<mso:button id=""ButtonVBM"" label=""Run VBM"" size=""large"" onAction=""RunVBM"" getImage=""GetImage"" />" & _
    "</mso:group >"
    "<mso:group id=""AdvantageVBM"" label=""Advantage VBM"">" & _
    "<mso:button id=""ButtonNewOl"" label=""Create New Document"" size=""large"" onAction=""VBMOutlook"" getImage=""GetImage"" getVisible=""VBM_GetVisible"" />" & _
    "<mso:button id=""ButtonImportContacts"" label=""Save Selected Contacts"" size=""large"" onAction=""VBMOutlook"" imageMso=""DistributionListAddNewMember"" getVisible=""VBM_GetVisible"" />" & _
    "<mso:button id=""ButtonImportNotes"" label=""Save Selected Notes"" size=""large"" onAction=""VBMOutlook"" imageMso=""DistributionListAddNewMember"" getVisible=""VBM_GetVisible"" />" & _
    "<mso:button id=""ButtonImportTasks"" label=""Save Selected Tasks"" size=""large"" onAction=""VBMOutlook"" imageMso=""AccessTableTasks"" getVisible=""VBM_GetVisible"" />" & _
    "<mso:button id=""ButtonImportAppointments"" label=""Save Selected Appointments"" size=""large"" onAction=""VBMOutlook"" imageMso=""CopyToPersonalCalendar"" getVisible=""VBM_GetVisible"" />" & _
    "<mso:separator id=""separator1"" getVisible=""VBM_GetVisible"" />" & _
    "<mso:button id=""ButtonSend"" size=""large"" getImage=""GetImage"" getVisible=""VBM_GetVisible"" />" & _
    "<mso:button id=""ButtonImportEmails"" label=""Save Selected Emails"" size=""large"" onAction=""VBMOutlook"" imageMso=""SaveSentItemsMenu"" getVisible=""VBM_GetVisible"" />" & _
    "<mso:button id=""ButtonImportAttachments"" label=""Save All Attachments"" size=""large"" onAction=""VBMOutlook"" imageMso=""SaveAttachments"" getVisible=""VBM_GetVisible"" />" & _
    "</mso:group >"
    "<mso:group id=""VBMHelp"" label=""Help"">" & _
    "<mso:button id=""ButtonHelp"" label=""VBM Help Guide"" size=""large"" onAction=""VBMHelpGuide"" getImage=""GetImage"" />" & _
    "</mso:group >"
    "</mso:tab>" & _
    "</mso:tabs>" & _
    "</mso:ribbon>" & _
    "</mso:customUI>"

    End Sub

    Private Sub VBM_GetVisible(ByVal control As IRibbonControl, ByRef visible)

       
        visible = False
       
        Select Case gsOLFolderName
                
           Case conOLInbox
          
                Select Case control.ID
               
                    Case "ButtonNewOl", "ButtonImportEmails", "ButtonImportAttachments", "separator1":  visible = True
                       
                End Select
           
           Case conOLCalendar
          
                Select Case control.ID
               
                    Case "ButtonImportAppointments": visible = True
                       
                End Select
          
           Case conOLContacts
          
                Select Case control.ID
               
                    Case "ButtonImportContacts": visible = True
                       
                End Select
                 
           Case conOLToDoList
          
                Select Case control.ID
               
                    Case "ButtonImportTasks": visible = True
                       
                End Select
               
           Case conOLNotes
          
                Select Case control.ID
               
                    Case "ButtonImportNotes": visible = True
                       
                End Select
       
        End Select

    End Sub

    Thanks in advance

    Mike


    Michael McGinty CY Innovations Pty Ltd Publisher of Advantage VBM - Your Business Advantage

    Wednesday, July 18, 2012 10:21 AM
  • Do you get the call for the Explorer ribbon XML and supply it?
     
    You get 1 ribbon OnLoad() callback where you set your global Ribbon object. What I usually do is call Invalidate on the ribbon object when I get the Activate() event on a new Explorer, and the BeforeFolderSwitch() event on existing Explorers.
     
    In the callbacks such as getVisible or getEnabled and so on you get passed a control object. The control.Context is either Explorer or Inspector. In C#:
     
    if (control.Context is Outlook.Explorer)
    {
        // now check for control.ID to see which control is firing the callback this time
    }
    else if (control.Context is Outlook.Inspector)
    {
    }
     
    In your example with FolderSwitch():

    Private Sub myOlExp_FolderSwitch()

        gsOLFolderName = myOlExp.CurrentFolder.Name

        g_Ribbon.Invalidate() ' or invalidate each desired control individually
    End Sub

    In Outlook 2010, where the Explorer uses the ribbon, you will get your ribbon OnLoad() callback as soon as the UI is established, assuming Outlook was started with a UI and not from a Simple MAPI call. In Outlook 2007 you wouldn't get that callback until the first Inspector was opened, which could be a long time after Outlook was started if it wasn't started with Simple MAPI.

    --
    Ken Slovak
    [MVP-Outlook]
    http://www.slovaktech.com
    Author: Professional Programming Outlook 2007
    "Mike McGinty" <=?utf-8?B?TWlrZSBNY0dpbnR5?=> wrote in message news:ad0d1f6c-0b3f-4277-86cf-0c31033f412b...

    I'm having trouble calling the InvalidateControl methods when the user selects another folder on the Outlook Explorer

    How/where do I instantiate m_Ribbon just for the Explorer ribbon and where should the following calls be located in the code?

    if ribbonID = "Microsoft.Outlook.Explorer" then

       m_Ribbon.InvalidateControl ("ButtonNewOl")
       m_Ribbon.InvalidateControl ("ButtonImportEmails")
       m_Ribbon.InvalidateControl ("ButtonImportAttachments")
       m_Ribbon.InvalidateControl ("separator1")
       m_Ribbon.InvalidateControl ("ButtonImportAppointments")
       m_Ribbon.InvalidateControl ("ButtonImportContacts")
       m_Ribbon.InvalidateControl ("ButtonImportTasks")
       m_Ribbon.InvalidateControl ("ButtonImportNotes")

    end if


    The following code is located in a class module and works correctly each time an new folder is selected on the Outlook explorer
    According to Microsoft this must be placed in a class module
    Public WithEvents myOlExp As outlook.Explorer

    Private Sub myOlExp_FolderSwitch()


        gsOLFolderName = myOlExp.CurrentFolder.Name


    End Sub

    The following code is located in a designer module. All ribbons correctly load depending on the type of inspector
    Implements IRibbonExtensibility

    Public Function IRibbonExtensibility_GetCustomUI(ByVal ribbonID As String) As String

        Select Case ribbonID
       
            Case "Microsoft.Outlook.Explorer"
       
                IRibbonExtensibility_GetCustomUI = GetRibbonXMLExplorer()
       
            Case "Microsoft.Outlook.Mail.Read"
       
                IRibbonExtensibility_GetCustomUI = GetRibbonXMLRead()
       
            Case "Microsoft.Outlook.Contact"
       
                IRibbonExtensibility_GetCustomUI = GetRibbonXMLContact()
           
            Case "Microsoft.Outlook.Appointment"
       
                IRibbonExtensibility_GetCustomUI = GetRibbonXMLAppointment()
           
            Case "Microsoft.Outlook.Task"
       
                IRibbonExtensibility_GetCustomUI = GetRibbonXMLTask()
           
            Case Else
       
                IRibbonExtensibility_GetCustomUI = GetRibbonXMLDefault()
       
        End Select

    End Function

    Private sub GetRibbonXMLExplorer ()
       
    "<mso:customUI xmlns:mso=""http://schemas.microsoft.com/office/2006/01/customui"" onLoad=""Ribbon_OnLoad"" >" & _
    "<mso:ribbon>" & _
    "<mso:tabs>" & _
    "<mso:tab id=""CustomTab"" label=""VBM"" insertAfterMso=""TabHome"" >" & _
    "<mso:group id=""RunVBM"" >" & _
    "<mso:button id=""ButtonVBM"" label=""Run VBM"" size=""large"" onAction=""RunVBM"" getImage=""GetImage"" />" & _
    "</mso:group >"
    "<mso:group id=""AdvantageVBM"" label=""Advantage VBM"">" & _
    "<mso:button id=""ButtonNewOl"" label=""Create New Document"" size=""large"" onAction=""VBMOutlook"" getImage=""GetImage"" getVisible=""VBM_GetVisible"" />" & _
    "<mso:button id=""ButtonImportContacts"" label=""Save Selected Contacts"" size=""large"" onAction=""VBMOutlook"" imageMso=""DistributionListAddNewMember"" getVisible=""VBM_GetVisible"" />" & _
    "<mso:button id=""ButtonImportNotes"" label=""Save Selected Notes"" size=""large"" onAction=""VBMOutlook"" imageMso=""DistributionListAddNewMember"" getVisible=""VBM_GetVisible"" />" & _
    "<mso:button id=""ButtonImportTasks"" label=""Save Selected Tasks"" size=""large"" onAction=""VBMOutlook"" imageMso=""AccessTableTasks"" getVisible=""VBM_GetVisible"" />" & _
    "<mso:button id=""ButtonImportAppointments"" label=""Save Selected Appointments"" size=""large"" onAction=""VBMOutlook"" imageMso=""CopyToPersonalCalendar"" getVisible=""VBM_GetVisible"" />" & _
    "<mso:separator id=""separator1"" getVisible=""VBM_GetVisible"" />" & _
    "<mso:button id=""ButtonSend"" size=""large"" getImage=""GetImage"" getVisible=""VBM_GetVisible"" />" & _
    "<mso:button id=""ButtonImportEmails"" label=""Save Selected Emails"" size=""large"" onAction=""VBMOutlook"" imageMso=""SaveSentItemsMenu"" getVisible=""VBM_GetVisible"" />" & _
    "<mso:button id=""ButtonImportAttachments"" label=""Save All Attachments"" size=""large"" onAction=""VBMOutlook"" imageMso=""SaveAttachments"" getVisible=""VBM_GetVisible"" />" & _
    "</mso:group >"
    "<mso:group id=""VBMHelp"" label=""Help"">" & _
    "<mso:button id=""ButtonHelp"" label=""VBM Help Guide"" size=""large"" onAction=""VBMHelpGuide"" getImage=""GetImage"" />" & _
    "</mso:group >"
    "</mso:tab>" & _
    "</mso:tabs>" & _
    "</mso:ribbon>" & _
    "</mso:customUI>"

    End Sub

    Private Sub VBM_GetVisible(ByVal control As IRibbonControl, ByRef visible)

       
        visible = False
       
        Select Case gsOLFolderName
                
           Case conOLInbox
          
                Select Case control.ID
               
                    Case "ButtonNewOl", "ButtonImportEmails", "ButtonImportAttachments", "separator1":  visible = True
                       
                End Select
           
           Case conOLCalendar
          
                Select Case control.ID
               
                    Case "ButtonImportAppointments": visible = True
                       
                End Select
          
           Case conOLContacts
          
                Select Case control.ID
               
                    Case "ButtonImportContacts": visible = True
                       
                End Select
                 
           Case conOLToDoList
          
                Select Case control.ID
               
                    Case "ButtonImportTasks": visible = True
                       
                End Select
               
           Case conOLNotes
          
                Select Case control.ID
               
                    Case "ButtonImportNotes": visible = True
                       
                End Select
       
        End Select

    End Sub

    Thanks in advance

    Mike


    Michael McGinty CY Innovations Pty Ltd Publisher of Advantage VBM - Your Business Advantage


    Ken Slovak MVP - Outlook
    Wednesday, July 18, 2012 1:56 PM
    Moderator
  • Thanks Ken

    If I use visible="True" instead of getVisible= the Explorer ribbon with the custom VBM tab and buttons loads correctly whenever Outlook starts

    I can now see how setting m_ribbon in the Ribbon_OnLoad callback works.

    I would need to make m_ribbon a global variable in order to use it to invoke InvalidateControl from  myOlExp_FolderSwitch() as it is located in a separate class module. Or else Dim and Set myOlExp plus relocate myOlExp_FolderSwitch() to the Add-in designer module where  IRibbonExtensibility_GetCustomUI () and the callbacks live

    Thanks for your help


    Michael McGinty CY Innovations Pty Ltd Publisher of Advantage VBM - Your Business Advantage

    Wednesday, July 18, 2012 2:33 PM
  • Using "visible="true" is fixed and doesn't depend on a ribbon callback, just having the original ribbon XML requested.
     
    The getVisible() callback will be called both on the first use of that ribbon as well as when an invalidate action is called. If you have 2 controls and just use Invalidate() getVisible() would be called twice, and so on.
     
    What's not working if you use getVisible()? Is the callback called?

    --
    Ken Slovak
    [MVP-Outlook]
    http://www.slovaktech.com
    Author: Professional Programming Outlook 2007
    "Mike McGinty" <=?utf-8?B?TWlrZSBNY0dpbnR5?=> wrote in message news:0f067bd7-c24b-465c-baae-a496097b6e91...

    Thanks Ken

    If I use visible="True" instead of getVisible= the Explorer ribbon with the custom VBM tab and buttons loads correctly whenever Outlook starts

    I can now see how setting m_ribbon in the Ribbon_OnLoad callback works.

    I would need to make m_ribbon a global variable in order to use it to invoke InvalidateControl from  myOlExp_FolderSwitch() as it is located in a separate class module. Or else Dim and Set myOlExp plus relocate myOlExp_FolderSwitch() to the Add-in designer module where  IRibbonExtensibility_GetCustomUI () and the callbacks live

    Thanks for your help


    Michael McGinty CY Innovations Pty Ltd Publisher of Advantage VBM - Your Business Advantage


    Ken Slovak MVP - Outlook
    Wednesday, July 18, 2012 2:57 PM
    Moderator
  • Ken

    It all works now. I was using the VBA callback function for getVisible() instead of the VB callback

    getVisible

    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

    I also relocated myOlExp_FolderSwitch() into the designer module where the callbacks live to avoid having to make m_ribbon a global

    Thanks very much for your help. Much appreciated

    Mike


    Michael McGinty CY Innovations Pty Ltd Publisher of Advantage VBM - Your Business Advantage

    Thursday, July 19, 2012 2:00 AM