1

I am developing outlook add-in for which I have to track appointment item add, change & remove events. So I am using bellow code.

   public Microsoft.Office.Interop.Outlook.Application app = null;
   public Outlook.NameSpace ns = null;
   public Outlook.MAPIFolder calendar = null;
   public Outlook.Items appointments = null;

private void ThisAddIn_Startup(object sender, System.EventArgs e) 
{
    app = Application;
    ns = app.GetNamespace("mapi");
    ns.Logon("", "", true, true);
    calendar = ns.GetDefaultFolder(OlDefaultFolders.olFolderCalendar);
    appointments = calendar.Items;

    appointments.ItemAdd += Item_Add;
    appointments.ItemChange += Item_Change;
    appointments.ItemRemove += Item_Remove;
}

private void Item_Add(object item) 
{
   // some logic
}

private void Item_Change(object item) 
{
  // some logic
}

private void Item_Remove() 
{
  // some logic
}

Now when I add meeting at that time Item_Add event is called.

When I update that created meeting then Item_Change event is fired 2 times.

I not able to get why it is firing 2 times.

Can any one give possible reason for it ?

vaibhav shah
  • 4,939
  • 19
  • 58
  • 96

3 Answers3

0

First of all, I'd recommend declaring the Items object at the global scope to make sure it is not swiped by the garbage collector. For example, you may declare the Items object outside of the Startup event handler.

The ItemChange event of the Items class is fired when an item in the specified collection is changed. So, it is fired each time you change any property.

Eugene Astafiev
  • 47,483
  • 3
  • 24
  • 45
  • As per your suggestion I declared all objects outside startup method. Yes Item_Change should be fired when i change applicationitem. But even after just updating subject in appointment item it is firing 2 times. – vaibhav shah Aug 26 '15 at 07:45
0

The event gets fired more than once if the item is saved multiple times. You should be prepared to handle situations like.

What does your event handler supposed to do? Why is this a problem?

Dmitry Streblechenko
  • 62,942
  • 4
  • 53
  • 78
  • Even if I update subject of item , Item_Change event gets fired 2 times. Even if I do not add any logic inside event handlers this thing happens. I really do not know why is this kind of thing is happening – vaibhav shah Aug 26 '15 at 07:47
  • Again, why is this a problem? What does you event handler do that causes a problem if the event is fired more than once? – Dmitry Streblechenko Aug 26 '15 at 15:40
  • my event handler sends request to some web service when there is change in item. so it sends same request 2 times. – vaibhav shah Aug 26 '15 at 18:19
  • It would be a good idea to buffer requests - use a timer (from the Forms namespace). In the ItemChange event handler, disable then enable the timer. When the timer fires (a few seconds later), send the data to the web service. This way if ItemChange fires more than once in a period of time less than the timer interval, you will upload the changes only once. – Dmitry Streblechenko Aug 26 '15 at 18:23
  • That being said, Items events (based on the IMAPITable MAPI events) should never be used for any kind of synchronization. MAPI events were designed for the UI purposes only; they can be dropped under heavy loads. And event can only be used as a hint that you need to sync sooner rather than later. – Dmitry Streblechenko Aug 26 '15 at 18:25
  • What actually I want to do is that when ever some one creates, updates or removes meetings/appointments then it should do some manipulations & call some web service. If I can not use Items events , then can you suggest what should I do ? – vaibhav shah Aug 27 '15 at 06:52
  • Under Exchange, you can use the ICS (Incremental Change Synchronization) API (C++ or Delphi only). Redemption (any language) exposes that functionality through the RDOFolderSynchronizer object - http://www.dimastr.com/redemption/rdofoldersynchronizer.htm. Under stores other than Exchange periodically scanning the folder is the only way. – Dmitry Streblechenko Aug 27 '15 at 06:57
0

I haven't found any completely clear solution. The best idea which I implemented was to create list of Tasks which already had been processed and set the time validity for them.

At the beginning of the event I check if any of the processed task is outdated and remove it from the list. This way I keep list small and protect against memory leak.

class TaskItem
{
    private int milisecods = 200;
    DateTime Now
    {
        get
        {
            return DateTime.Now;
        }
    }

    public TaskItem()
    {
        this.Created = Now;
    }

    private DateTime Created;

    public string EntryId { get; set; }

    public bool OutDated
    {
        get
        {
            return this.Created.AddMilliseconds(milisecods) > Now;
        }
    }
}

List<TaskItem> TaskItemsList = new List<TaskItem>();

private void TaskItems_ItemChange(object Item)
{
    this.TaskItemsList.RemoveAll(x => x.OutDated);
    MailItem element = Item as MailItem;
    if (element != null)
    {
        if (element.FlagStatus == OlFlagStatus.olFlagComplete)
        {
            if (this.TaskItemsList.Any(x => x.EntryId == element.EntryID) == false)
            {
                this.TaskItemsList.Add(new TaskItem { EntryId = element.EntryID });
                new WcfClient().ProcesOutlookTask(TaskActionType.Finished);
            }
        }
    }
}

If you are interested in the working solution you can find above code in the repository.

Pawel Wujczyk
  • 422
  • 3
  • 12