views:

228

answers:

2

Hello,

I'm having some trouble getting a web-page indexing program to work. I have a form that automatically downloads URLs to index from a database server and sends back responses containing the indexed page information, over UDP. I have a static class called UDP that keeps track of incoming and outgoing messages. There is an event that fires whenever a message is recieved, which the form that contains all the indexing code hooks to keep track of messages sent from a program on the server that holds the database of urls to index.

This was all working fine, until I added another form that appears before the indexing form. Now, the indexing form opens on another thread (through Application.Run() and a second thread). The problem is, the event handler is no longer called when the event is fired.

So, the question is, what is going on here, and what can I do to fix it? I'm pretty sure it has to do with some cross-thread safety mechanism that doesn't call event handlers on another thread than the one the event was fired from. Does anybody know of a different way to do this or a way to circumvent this? Thanks in advance...

+3  A: 

An UI control has to be manipulated on the thread that it was created on (the UI thread). In order to achieve that, you'll have to 'invoke' the event-handler.

This can be done by raising the event like this:

EventHandler handler = myEventHandler;
if( handler != null )
{
    ISynchronizeInvoke target = handler.Target as ISynchronizeInvoke;

    if( target != null && target.InvokeRequired )
    {
        target.Invoke (handler, ... );
    }
    else
    {
        handler.DynamicInvoke (...);
    }
}

Or, you can also have a look at the AsyncOperation & AsyncOperationManager classes.

Or, perhaps even simpler, take a look at the SynchronizationContext class. Using the 'Current' property of this class, you can just Post a SendOrPostCallback delegate which wraps around your eventhandler.

Frederik Gheysels
There is not usually any need to use DynamicInvoke here - just invoke it. It is also more common for the *target* to do this...
Marc Gravell
A: 

I don't think this is a "safety mechanism". The safety mechanism that does exist in WinForms (from .NET 2.0 onwards) throws an exception if you're in the debugger and you try to access the UI from a thread other than the appropriate one.

Are you sure that the event isn't being called at all? That sounds extremely strange. If you put a breakpoint on the event handler in the debugger, does that break point not get hit?

To answer your question in a different way though, I wouldn't make the entire event handler execute on a specific thread. There may be more than one handler subscribed, and those handlers may need to execute on different threads. Instead, I would make the event handlers themselves thread-safe - code them so that if they need to perform some action on a particular thread, they do the marshalling back to the thread (e.g. with Control.BeginInvoke etc).

Which thread is most of your network access taking place on? I would hope it's not either of the UI threads involved (as otherwise you can get an unresponsive UI). That would mean that if it was working before, you're probably already doing the appropriate marshalling... very strange.

If none of this helps, could you try to come up with a short but complete program which demonstrates the problem? It's easier to diagnose concrete code :)

Jon Skeet