xmlvstooutlook-addinribbon

Synchronize Ribbon (XML) Togglebutton with CustomTaskPane


I know I might be a bit late to the party, but unfortunately I still have to write a COM Add-in for Outlook. Because I need a contextual ribbon I have to use XML and not the designer.

All that is missing is to sync the toggle button in my ribbon (multiple inspectors possible) with the custom task pane visible_change event in ThisAddin class. So when I close the CustomTaskPane in an inspector, the toggle button is resetting to not pressed. I googled for days already and am surprised, that no one posted a solution for that (unless there is none). It's a shame the documentation doesn't cover that for XML at all.

Thanks for any help!

I tried this and a bunch of other similar questions but it doesn't seem to work.

I followed the MS Docs for multi-window Taskpanes. So this is in my ThisAddin.cs (void TaskPane_VisibleChanged(object sender, EventArgs e) is what is missing):

public class InspectorWrapper
{
    private Inspector inspector;
    private CustomTaskPane taskPane;

    public InspectorWrapper(Inspector Inspector)
    {
        inspector = Inspector;
        ((InspectorEvents_Event)inspector).Close +=
            new InspectorEvents_CloseEventHandler(InspectorWrapper_Close);
        
        taskPane = Globals.ThisAddIn.CustomTaskPanes.Add(
            new SignatureControl(Inspector), "Signatures", inspector);
        taskPane.VisibleChanged += new EventHandler(TaskPane_VisibleChanged);
    }

    void TaskPane_VisibleChanged(object sender, EventArgs e)
    {
        
    }

    void InspectorWrapper_Close()
    {
        if (taskPane != null)
        {
            Globals.ThisAddIn.CustomTaskPanes.Remove(taskPane);
        }

        taskPane = null;
        Globals.ThisAddIn.InspectorWrappers.Remove(inspector);
        ((InspectorEvents_Event)inspector).Close -=
        new InspectorEvents_CloseEventHandler(InspectorWrapper_Close);
        
        inspector = null;
    }

    public CustomTaskPane CustomTaskPane
    {
        get
        {
            return taskPane;
        }
    }
}

And this is my Ribbon:

public Ribbon1()
{
}

#region IRibbonExtensibility-Member

public string GetCustomUI(string ribbonID)
{
    if (ribbonID == "Microsoft.Outlook.Explorer")
    {
        return GetResourceText("Test.Ribbon1.xml");
    }
    if (ribbonID == "Microsoft.Outlook.Mail.Compose")
    {
        return GetResourceText("Test.MailComposeRibbon.xml");
    }

    return null;
}

#endregion

#region Callbacks

public void Ribbon_Load(Office.IRibbonUI ribbonUI)
{
    this.ribbon = ribbonUI;
}

public void toggleButton1_Click(Office.IRibbonControl control, bool pressed)
{ 
 Globals.ThisAddIn.InspectorWrappers[(Inspector)control.Context].CustomTaskPane.Visible = pressed;
}

For everyone else who is searching for this, this is how I solved it thanks to Dmitry's answer:

Create a property in ThisAddin.cs to hold the RibbonUI:

public IRibbonUI ribbonUI;

Fill it:

public void Ribbon_Load(Office.IRibbonUI ribbonUI)
{
    this.ribbon = ribbonUI;

    Globals.ThisAddIn.ribbonUI = ribbonUI;
}

Refresh ribbon, if visibility of your task pane changes:

void TaskPane_VisibleChanged(object sender, EventArgs e)
{
    Globals.ThisAddIn.ribbonUI.Invalidate();
}

Don't forget to define the getPressed Method for the toggle button:

<toggleButton id="toggleButton1" getPressed="toggleButton_GetPressed" onAction="toggleButton1_Click" label="Test" size="large" getImage="toggleButton_GetImage" />

And the method being called by that:

public bool toggleButton_GetPressed(IRibbonControl control)
{
    return WhatEverYourStatusShouldBe;
}

Solution

  • Please be more specific, show your existing code and describe what exactly you need to do.

    The standard solution is to cache IRibbonUI interface from onLoad callback of your customUI Ribbon XML element. When you need to change the state of a ribbon control, call IRibbonUI.Invalidate / IRibbonUI.InvalidateControl. That will force the ribbon to call various callbacks on your controls (getLabel, getVisible, etc.). Your code can then return appropriate values for your controls.