views:

36

answers:

1

I am creating an Outlook Mail Item object and watching for the Send event. All appears well, but when the Send event fires, the event is raised on the background thread of my application. The reason this is a problem is that this event creates a record of the email sent through my application, which is added to a collection of objects. The collection is therefore raising the List Changed event on the background thread causing a cross-thread control access on the control that displays the collection.

Here is my event hookup:

((Outlook.ItemEvents_10_Event)item).Send += new Microsoft.Office.Interop.Outlook.ItemEvents_10_SendEventHandler(ItemSendWatcher_Send);

The event is hooked up in a basic class which holds a reference to the message being sent, and a delegate to call when the send event is raised. This allows me to pass an instance of the email object to the delegate.

This is my handler:

void ItemSendWatcher_Send(ref bool Cancel)
    {
        if (itemSendDelegate != null)
        {
            this.itemSendDelegate(this.item, ref Cancel); //The delegate with the mail item
        }
        Marshal.ReleaseComObject(item);
        itemSendDelegate = null;
    }

Is this the correct behaviour for this event or am I doing something wrong when constructing the object? Thanks for any help.

Edit: Just to clarify, I am not handling the event in the UI layer, rather in a business object. The delegate called from the Send Event handler causes a new object to be added to a list internally, which causes the list's ListChanged event to be raised resulting in a handler being called in the control displaying this list. I hope this clarifies what I'm trying to achieve.

+1  A: 

A lot of Forms events are raised on the main window thread which means you often don't have to worry too much about cross thread concerns. However there are no guarantees and COM will usually not raise events on that thread. The solution is to call this.Invoke(..) with either a delegate to a method or an anonymous block to perform the necessary work on the right thread. To test whether or not this is necessary test this.InvokeRequired.

open-collar
Invoke and InvokeRequired are not available as the class is not a control. That's why I asked in a comment to a previous answer if I need to create an instance of a control to allow me to call Invoke.
GaryJL
You need to use Invoke on whatever it is you are changing within your handler - the control that is displaying the list.
open-collar
I see - that makes sense! The problem is, I don't have access to the control at any stage during the handling of the event, except maybe when the list changed event is raised in my collection class. Time to refactor I think!
GaryJL