如何使事件处理程序异步运行?
我正在编写一个 Visual C# 程序,该程序在辅助线程上执行连续的操作循环。有时,当该线程完成任务时,我希望它触发事件处理程序。我的程序就是这样做的,但是当事件处理程序被触发时,辅助线程会等待事件处理程序完成,然后再继续线程。我该如何让它继续下去?这是我目前的结构方式...
class TestClass
{
private Thread SecondaryThread;
public event EventHandler OperationFinished;
public void StartMethod()
{
...
SecondaryThread.Start(); //start the secondary thread
}
private void SecondaryThreadMethod()
{
...
OperationFinished(null, new EventArgs());
... //This is where the program waits for whatever operations take
//place when OperationFinished is triggered.
}
}
此代码是我的一台设备的 API 的一部分。当 OperationFinished 事件被触发时,我希望客户端应用程序能够执行所需的任何操作(即相应地更新 GUI),而无需拖拉 API 操作。
另外,如果我不想将任何参数传递给事件处理程序,使用 OperationFinished(null, new EventArgs())
的语法是否正确?
I am writing a Visual C# program that executes a continuous loop of operations on a secondary thread. Occasionally when that thread finishes a task I want it to trigger an eventhandler. My program does that but the when the event handler is triggered, the secondary thread waits until the event handler is finished before continuing the thread. How do I make it continue? Here is the way I currently have it structured...
class TestClass
{
private Thread SecondaryThread;
public event EventHandler OperationFinished;
public void StartMethod()
{
...
SecondaryThread.Start(); //start the secondary thread
}
private void SecondaryThreadMethod()
{
...
OperationFinished(null, new EventArgs());
... //This is where the program waits for whatever operations take
//place when OperationFinished is triggered.
}
}
This code is part of an API for one of my devices. When the OperationFinished event is triggered I want the client application to be able to do whatever it needs to (i.e. update the GUI accordingly) without haulting the API operation.
Also, if I do not want to pass any parameters to the event handler is my syntax correct by using OperationFinished(null, new EventArgs())
?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(7)
那么您想以防止侦听器阻塞后台线程的方式引发事件吗?给我几分钟时间来举一个例子;非常简单 :-)
我们开始吧:首先是一个重要的说明!每当您调用
BeginInvoke
时,您都必须调用相应的EndInvoke
,否则如果调用的方法抛出异常或返回一个值,那么ThreadPool线程将永远不会被释放回池中,从而导致线程泄漏!So you want to raise the event in a manner that prevents the listeners from blocking the background thread? Gimme a couple minutes to whip up an example; it's pretty simple :-)
Here we go: first an important note! Whenever you call
BeginInvoke
you must call the correspondingEndInvoke
, otherwise if the invoked method threw an exception or returned a value then the ThreadPool thread will never be released back to the pool, resulting in a thread-leak!使用任务并行库,现在可以执行以下操作:
With the Task Parallel Library it is now possible to do the following:
不。通常,您将其称为:
您应该始终将对象作为发送者传递 - 这是模式中所期望的(尽管通常会被忽略)。 EventArgs.Empty 也比 new EventArgs() 更好。
为了在单独的线程中触发此事件,最简单的选择可能是仅使用线程池:
也就是说,在单独的线程上引发事件应该被彻底记录,因为它可能会导致意外的行为。
No. Typically, you would call it as:
You should always pass an object as a sender - it's expected in the pattern (although typically ignored). EventArgs.Empty is better than new EventArgs(), as well.
In order to fire this in a separate thread, the easiest option is probably to just use the thread pool:
That being said, raising an event on a separate thread is something that should be thoroughly documented, as it will potentially cause unexpected behavior.
尝试事件委托上的 BeginInvoke 和 EndInvoke 方法 - 这些方法立即返回,并允许您使用轮询、等待句柄或回调函数在方法完成时通知您。请参阅此处了解概述;在您的示例中,事件是您将使用的委托
Try the BeginInvoke and EndInvoke methods on the event delegate - these return immediately, and allow you to use polling, a wait handle or a callback function to notify you when the method has completed. See here for an overview; in your example, the event is the delegate you'll be using
也许下面的方法2或方法3可以帮助:)
}
Maybe Method2 or Method3 below can help :)
}
我更喜欢定义一个方法,将其作为更新 UI 的委托传递给子线程。首先定义一个委托:
在子线程中定义一个委托成员:
在调用类中定义更新UI的方法。您需要将其包装在目标控件的调度程序中,因为它是从单独的线程调用的。请注意 BeginInvoke。在这种情况下,不需要 EndInvoke:
在启动子线程之前,设置其 ChildCallBack 属性:
然后当子线程想要更新父线程时:
I prefer to define a method that I pass to the child thread as a delegate which updates the UI. First define a delegate:
In the child thread define a delegate member:
In the calling class define the method that updates the UI. You'll need to wrap it in the target control's dispatcher since its being called from a separate thread. Note the BeginInvoke. In this context EndInvoke isn't required:
Before you launch your child thread, set its ChildCallBack property:
Then when the child thread wants to update the parent:
查看 BackgroundWorker 类。我认为它完全符合您的要求。
编辑:
我认为您要问的是当整个后台任务仅完成一小部分时如何触发事件。 BackgroundWorker 提供了一个名为“ProgressChanged”的事件,允许您向主线程报告整个过程的某些部分已完成。然后,当所有异步工作完成时,它会引发“RunWorkerCompleted”事件。
Look at the BackgroundWorker class. I think it does exactly what you are asking for.
EDIT:
What I think you are asking is how to fire an event when only a small part of the overall background task is complete. BackgroundWorker provides an event called "ProgressChanged" that allows you to report back to the main thread that some portion of the overall process is complete. Then, when all of the async work is complete, it raises the "RunWorkerCompleted" event.