简体   繁体   English

如何从单独的线程(而不是在创建该线程的线程)中调用事件处理程序?

[英]How Can I Get an Event Handler to be Called From a Seperate Thread than the One it Was Created On?

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. 我有一个表单,该表单会自动从数据库服务器下载URL进行索引,然后通过UDP发送包含已索引页面信息的响应。 I have a static class called UDP that keeps track of incoming and outgoing messages. 我有一个称为UDP的静态类,用于跟踪传入和传出消息。 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. 每当接收到一条消息时都会触发一个事件,该事件包含所有索引代码的钩子,用于跟踪从服务器上保存了要索引的url的程序发送的消息。

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). 现在,索引窗体在另一个线程上打开(通过Application.Run()和第二个线程)。 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... 提前致谢...

An UI control has to be manipulated on the thread that it was created on (the UI thread). UI控件必须在创建它的线程(UI线程)上进行操作。 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. 或者,您也可以查看AsyncOperationAsyncOperationManager类。

Or, perhaps even simpler, take a look at the SynchronizationContext class. 或者,也许更简单,看看SynchronizationContext类。 Using the 'Current' property of this class, you can just Post a SendOrPostCallback delegate which wraps around your eventhandler. 使用此类的'Current'属性,您只需发布环绕事件处理程序的SendOrPostCallback委托。

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. 如果您在调试器中,并且尝试从适当线程以外的线程访问UI, WinForms(从.NET 2.0起)中确实存在的安全机制将引发异常。

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 (eg with Control.BeginInvoke etc). 相反,我将使事件处理程序本身具有线程安全性-对它们进行编码,以便如果他们需要在特定线程上执行某些操作,则可以将它们编组回线程(例如,使用Control.BeginInvoke等)。

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). 我希望它不涉及任何一个UI线程(否则您将获得一个无响应的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 :) 诊断具体代码更容易:)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM