问题
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