Outlook VSTO Explorer.Selection_Change doesn not get called

馋奶兔 提交于 2021-01-29 14:40:21

问题


In my VSTO plugin I use the following class members to store pointers to currentExplorer, currentAppointmentItem and currentExplorers.

In Startup I try to setup all necessary event handlers like this:

currentExplorers = this.Application.Explorers;

foreach (Outlook.Explorer explorer in currentExplorers)
{
    ((Outlook.ExplorerEvents_10_Event)explorer).Activate +=
    new Outlook.ExplorerEvents_10_ActivateEventHandler(
    Explorer_Activate);

    explorer.Deactivate += new
    Outlook.ExplorerEvents_10_DeactivateEventHandler(
    Explorer_Deactivate);
}

currentExplorers.NewExplorer += New_Explorer;

My event handlers look like this:

void New_Explorer(Outlook.Explorer explorer)
        {
            if (currentExplorer != null)
            {
                Marshal.ReleaseComObject(currentExplorer);
            }
            currentExplorer = explorer;
            currentExplorer.SelectionChange += new Outlook.ExplorerEvents_10_SelectionChangeEventHandler(Selection_Change);
            currentExplorer.Deactivate += new Outlook.ExplorerEvents_10_DeactivateEventHandler(Explorer_Deactivate);

        }

        void Explorer_Deactivate()
        {
            if (currentExplorer != null)
            {
                currentExplorer.SelectionChange -= new Outlook.ExplorerEvents_10_SelectionChangeEventHandler(Selection_Change); ;
                Marshal.ReleaseComObject(currentExplorer);
                currentExplorer = null;
            }

        }

        void Explorer_Activate()
        {
            if (currentExplorer != null)
            {
                Marshal.ReleaseComObject(currentExplorer);
            }
            currentExplorer = this.Application.ActiveExplorer();
            currentExplorer.SelectionChange += new Outlook.ExplorerEvents_10_SelectionChangeEventHandler(Selection_Change);
        }


        private void Selection_Change()
        {
            if (currentExplorer == null)
            {
                return;
            }

            try
            {
                Outlook.MAPIFolder selectedFolder = currentExplorer.CurrentFolder;
                if (currentExplorer.Selection.Count > 0)
                {
                    Object selObject = currentExplorer.Selection[1];
                    if (selObject is Outlook.AppointmentItem)
                    {
                        if (currentAppointmentItem != null)
                        {
                            Marshal.ReleaseComObject(currentAppointmentItem);
                        }
                        currentAppointmentItem = (Outlook.AppointmentItem)selObject;
                    }
                    else
                    {
                        currentAppointmentItem = null;
                    }
                }
            } catch(Exception ex)
            {
                log.Error(ex.Message);
            }
        }

I setup break points on every event handler Problem is when I debug my Outlook plugin none of the event handlers gets called except for Explorer_Deactivate. When I debug in there I see the currentExplorer is still null, so I assume it gets called for some reason during initialization of outlook (at that time only the splash screen of Outlook is visible)

What I am doing wrong? I would have expected that each and every selection of any item (in Mail, Calendar etc.) will call Selection_Change but this is unfortunately not the case


回答1:


To get the events fired you must keep the source object alive all the time, so you need to declare the object reference at the global scope, i.e. class level.

You mixed two approaches in the code - Activate/Deactivate handlers and NewExplorer/Close events. As I previously wrote, instead of handling Activate and Deactivate events you can handle the NewExplorer event where you can subscribe to the Close and SelectionChange events. In the Close event handler you can unsubscribe from the SelectionChange event. So, you can develop an Explorer wrapper instead. See Implement a wrapper for inspectors and track item-level events in each inspector for more information.




回答2:


Eugene was partly right with his answer. To correctly use New_Explorer and Close_Explorer one needs to know to catch the Close Event you need to cast your Explorer like this:

    ((Outlook.ExplorerEvents_10_Event)currentExplorer).Close += new Outlook.ExplorerEvents_10_CloseEventHandler(Explorer_Close);

But the true reason why this didn't work is from what I understand: the Explorer refers to to the current Outlook Window. It is not completely sure that the Outlook window opens AFTER the ThisAddIn.Startup is done. Therefore the coding above will handle perfectly additional windows of Outlook but NOT the current one.

Therefore you need to manually call New_Explorer from within the Startup to initialize the currentExplorer member (of the class to keep the reference save from Garbage Colllection) with the ActiveExplorer() window like this.

New_Explorer(this.Application.ActiveExplorer());

This initializes not only the pointer to the currentExplorer but also sets up the Selection_Change() and the Close() event handler.

Now all selections events are handled correctly. Do keep in mind that Selection_Change seems to be fired multiple times:

  • https://www.add-in-express.com/forum/read.php?FID=5&TID=14216
  • In an Outlook 2013 C# VSTO project, why does the Explorer SelectionChange event fire twice

Unfortunately running this solution in Debugger the Addin still crashes when user double clicks on an appointment series and selects the single appointment. No exceptions fired. See this issue which is still valid: Outlook VSTO Handling SelectionChange correctly (currently doubleclick crashes Addin)



来源:https://stackoverflow.com/questions/61699431/outlook-vsto-explorer-selection-change-doesn-not-get-called

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!