ItemChange in Outlook VSTO AddIn gets called several times after save to appointmentItem - vsto

in my Addin I attached to the ItemChange event like this;
public void attachEvents()
{
_CalendarItems.ItemChange += Item_Change;
and I wrote a function like this:
public void Item_Add(Object item)
{
Outlook.AppointmentItem myAppointment = item as Outlook.AppointmentItem;
if (myAppointment != null)
{
[...]
My problem is that this method does not get called just once when I call myAppointment.save() but 3-4 times. Why is that?
And there are only get() calls in the eventhandler so there is NOTHING changed in the appointmentItem (which would probably trigger further events of course).
Best regards
Hannes

That is expected. Especially with Exchange profiles configured in Outlook. You may find similar forum threads like the following one - Outlook 2016 produces an extra ItemChange event after an appointment is created.

Related

Outlook VSTO Addin - NormalEmail.dotm not saved

I'm trying to register a handler for the WindowSelectionChanged event. It works, but when quitting Outlook, it will discard any changes to NormalEmail.dotm file.
For example, any changes to the Quick Part Gallery (Insert->Text->QuickParts) will only be visible during the current session; closing Outlook and starting it again will show the previous list of elements, even if they were deleted, or new ones were added).
Deleting the file :
C:\Users[USER]\AppData\Roaming\Microsoft\Templates\ NormalEmail.dotm
should prompt Outlook to create a new one, but this won't happen when the Addin is enabled.
This can be reproduced by registering even an empty method to the WindowSelectionChange event:
public partial class ThisAddIn
{
private void ThisAddIn_Startup(object sender, System.EventArgs e)
{
this.Application.Inspectors.NewInspector += new Outlook.InspectorsEvents_NewInspectorEventHandler(RegisterChangeHandler);
}
void RegisterChangeHandler(Outlook.Inspector inspector)
{
Microsoft.Office.Interop.Word.Application app = Application.ActiveExplorer().ActiveInlineResponseWordEditor?.Application;
--> app.WindowSelectionChange += WinSelectionChange; <-- this line causes the bug
}
private void WinSelectionChange(Selection Sel)
{
/* nothing */
}
...
}
This causes no exceptions; the result is the same when putting try/catch blocks in place, or when the callback is unregistered in the Application.Quit event.
Question: How can Outlook be made to commit the NormalEmail.dotm file, while also being able to register a callback for WindowSelectionChange event ?
(the project type is "2013 and 2016 VSTO Addin")

MailItem event not firing without Visual Studio

I want to handled the BeforeAttachmentAdd event from an Outlook mail item. But my code works in Visual Studio environment but not out. Have you an idea?
This is my code:
namespace MyOutlookProject
{
using Microsoft.Office.Interop.Outlook;
using OutlookApplication = Microsoft.Office.Interop.Outlook.Application;
using OutlookAttachment = Microsoft.Office.Interop.Outlook.Attachment;
using OutlookInspector = Microsoft.Office.Interop.Outlook.Inspector;
using OutlookMail = Microsoft.Office.Interop.Outlook.MailItem;
class MailManager
{
public void StartUp(OutlookApplication application)
{
_inspectors = application.Inspectors;
_inspectors.NewInspector += Inspectors_NewInspector;
}
private void Inspectors_NewInspector(OutlookInspector Inspector)
{
if (Inspector.CurrentItem is OutlookMail)
{
OutlookMail mail = (Inspector.CurrentItem as OutlookMail);
mail.BeforeAttachmentAdd += Mail_BeforeAttachmentAdd;
}
}
private void Mail_BeforeAttachmentAdd(OutlookAttachment Attachment, ref bool Cancel)
{
/*Never called without Visual Studio*/
}
}
}
Thanks for your help.
The object firing the events (mail variable in your code) must be on the global/class level to prevent it from being garbage collected. The variable is local in you case.
On a general note, you can have multiple inspectors open, so it might make sense to have a wrapper object that holds references to the inspector and its mail item, and have a list of such wrappers in your addin.
From what I see you may be hitting a My button stopped working issue
From the book Of E. Carter and E. Lippert VSTO 2007
It states
One issue commonly encountered when beginning to program agains Office events in .NET is known as the "my button stopped working" issue. A developer will write some code to handle a Click event raised by a CommandBarButton in the Office toolbar object model. This code will sometimes work temporarily but then stop. The user will click the button, but the Click event appears to have stopped working. The cause of this issue is connecting an event handler to an object whose lifetime does not match the desired lifetime of the event. This tipcally occurs when the object to which you are connecting an event handler goes out of scope or gets sets to null so that it gets garbage collected.
I think in your case that the .NET RCW object of type OulookMail manipulated with variable mail that is the culprit. Its lifetime is not properly handled. The fact that this does not happen in Visual Studio is that you are probably in Debug mode that changes a little the Garbage Collection so your object is not destroyed yet when you do the testing.

is it possible to call an event receiver from an event receiver with different properties?

I have an event receiver that runs when metadata on a folder (docset) is updated. In the same event receiver, I want to run kick off an event receiver for each document in the folder. What I want to know is: is it possible to call an event receiver using a different SPitemEventProperties than the one given.
e.g.
public override void ItemUpdated (SPItemEventProperties properties) {
// when properties is/contains a folder:
// on each document in the folder
// run ItemUpdated where properties is a/contains a document
}
Is it possible to do this? If so, any ideas?
Short answers: no. There is possibly a really hacky way to do it but no obvious solution.
For my particular situation, it was easier to setup the environment so the document inherits the changing piece of metadata so it's event receiver fires when this column changes.
Hope it helps someone else in the future, or for my own records if no one else reads this.
You can call SPListItem.Update() on each document folder ItemUpdatedER. This run document EventReceiver.
public override void ItemUpdated (SPItemEventProperties properties) {
query all sub items/documents
on each document change your data:
item["customField"] = "update value";
item.Update() //call recursively ItemUpdating/ItemUpdate
}

How to make a propertysheetpage be a selection provider?

I've got a contributed command and a handler for it. The handler's execute event has to get the value for the property actually selected in the properties view and act on it, or to be disabled if no property selected.
I've tried:
1) Set the selection provider to something which provides selection from the property view. Something in this case is just PropertySheetViewer for my PropertySheetPage, but i can't set it as the selection provider because the PropertySheetPage's viewer is private and has no getter.
2) Overriding PropertySheetPage's createControl method: This method creates a Tree control for the PropertySheetViewer. A selection listener can be installed for that tree control, so maybe i can make my command handler implement SelectionListener... The solution would be somethin like:
In my editor:
public Object getAdapter(#SuppressWarnings("rawtypes") Class type) {
if (type == IPropertySheetPage.class) {
PropertySheetPage page = new PropertySheetPage() {
#Override
public void createControl(Composite parent) {
super.createControl(parent);
IHandler handler = someWayToGetMyCmdHandler();
((org.eclipse.swt.widgets.Tree) getControl())
.addSelectionListener(handler);
}
};
IPropertySheetEntry entry = new UndoablePropertySheetEntry(
getCommandStack());
page.setRootEntry(entry);
return page;
}
return super.getAdapter(type);
}
And my command handler implementing SelectionListener as i said... The problem with this approach is that i can't find a way to get a reference to my contributed command handler (someWayToGetMyCmdHandler() above).
Has anybody got any clue on this, or any other possible approach to the problem??
There's handleEntrySelection(ISelection selection) method in PropertySheetPage that you could override to be notified about selection changes in the viewer (although PropertySheetPage is #noextend).
The second part (updating the handler) is a bit more tricky than it would normally be. Commands/handlers get updated automatically when workbench selection changes (you just need to implement setEnabled(Object evaluationContext) AbstractHandler). But since PropertySheetPage is designed to change its input on global selection change, then you have to find some custom way to notify/update your handler.
As I understand, it is currently not possible to extend the platform command event handling mechanism with custom variables, so you just need to directly look up your handler using IHandlerService of the workbench.

Why does my VSTO Outlook Add-In hang on first run?

I've written this little MS Outlook 2003 VSTO Add-In using C# and Visual Studio 2008. It is meant to check each Mail Item being sent for the word "attach" in the body and if found, then check the number of attachments. If that number is zero, then ask the user if they really mean to send the message. It's supposed to work like the Gmail labs feature which does the same thing.
The odd thing is that it works, but the first time I run it, I get a pause, like the mail item window is hung for about 45 seconds. Once it gets past that, it runs very fast for the rest of the time I have Outlook open. If I close Outlook though, then the next time I re-open it and send a message, I will have this wait again.
Any ideas, peoples?
Here's the code for my Add-In:
namespace OutlookAttacher
{
public partial class ThisAddIn
{
private void ThisAddIn_Startup(object sender, System.EventArgs e)
{
this.Application.ItemSend += new Outlook.ApplicationEvents_11_ItemSendEventHandler(Application_ItemSend);
}
private void ThisAddIn_Shutdown(object sender, System.EventArgs e)
{
}
void Application_ItemSend(object Item, ref bool Cancel)
{
if (Item is Microsoft.Office.Interop.Outlook.MailItem)
{
Microsoft.Office.Interop.Outlook.MailItem currentItem = Item as Microsoft.Office.Interop.Outlook.MailItem;
Cancel = true;
if (currentItem.Body.Contains("attach"))
{
if (currentItem.Attachments.Count > 0)
{
Cancel = false;
//MessageBox.Show("This message will be sent now.");
currentItem.Send();
}
else
{
DialogResult ans = MessageBox.Show("This message has no attachments. Are you sure you want to send it?", "OutlookAttacher", MessageBoxButtons.YesNo);
if (ans.Equals(DialogResult.Yes))
{
Cancel = false;
//MessageBox.Show("This message will be sent now.");
currentItem.Send();
}
}
}
else
{
Cancel = false;
//MessageBox.Show("This message will be sent now.");
currentItem.Send();
}
}
}
}
}
Any suggestions for improving the code are welcome as well, since this is my first stab at an Outlook Add-In.
Update: I am running this on a 5-year Dell laptop, 2 GB of Ram and I-don't-know-which Intel CPU. I like the idea of adding a trace / debugging it. I will have to go figure out how to step through the code so I can see where it might be taking the longest time. Thanks y'all!
OK, I'm really embarrassed. The delay I was seeing was just Outlook synching with my Exchange server. I was at home when I was testing and Outlook was still connecting via HTTP. I am seeing it work fast today, in the office, so no HTTP. Thanks for the replies anyway.
:-)