2

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.

GaryJL
  • 901
  • 1
  • 11
  • 24

2 Answers2

1

You need to handle InvokeRequired + Invoke inside ItemEvents_10_SendEventHandler()

H H
  • 263,252
  • 30
  • 330
  • 514
  • I assume you mean create an instance of a control in the class which will allow me to invoke the handler using control.Invoke? – GaryJL Sep 03 '10 at 12:01
  • No, just look up how to use Control.Invoke and InvokeRequired. Nothing special about creating the control(s). Post the code for the eventhandler to get a better answer. – H H Sep 03 '10 at 12:17
  • Code for the event handler is in the question. – GaryJL Sep 03 '10 at 12:21
  • More info added to the question. – GaryJL Sep 03 '10 at 13:00
1

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
  • 1,404
  • 1
  • 16
  • 22
  • 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 Sep 03 '10 at 12:33
  • You need to use Invoke on whatever it is you are changing within your handler - the control that is displaying the list. – open-collar Sep 03 '10 at 12:38
  • 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 Sep 03 '10 at 12:46