如果对象已创建,并在一个线程中分配了事件,然后从另一个线程运行事件
本文关键字:事件 线程 分配 然后 运行 另一个 一个 创建 对象 如果 | 更新日期: 2023-09-27 17:56:33
如果我在主 UI 线程中创建一个对象,
然后从其他线程调用该对象中的方法,引发的任何事件是否会在单独的线程或主 UI 线程中运行?
例:
WebClient client = new WebClient();
client.DownloadDataCompleted += new DownloadDataCompletedEventHandler(
delegate(object sender, DownloadDataCompletedEventArgs e)
{
Thread.Sleep(60000);
});
BackgroundWorker worker = new BackgroundWorker();
worker.DoWork += new DoWorkEventHandler(
delegate(object sender, DoWorkEventArgs e)
{
Thread.Sleep(60000);
client.DownloadDataAsync("http://www.example.com");
});
worker.RunWorkerAsync();
将事件与他们自己的方法而不是委托联系起来会有什么不同吗?
谢谢。
事件在调用它的线程上同步引发,也就是说,事件的所有订阅者都在引发事件的线程中运行。
您也可以通过 BeginInvoke 异步引发事件,在这种情况下,我相信它"最终"由应用程序线程池中的线程处理。
您需要保护与任何 UI 组件交互的任何处理程序,防止在与主 UI 线程不同的线程上执行。
您可以通过 Control.InvokeRequired/Control.Invoke(...) 技术执行此操作,请参阅
事件处理程序在调用它们的线程上运行,就像任何其他方法一样。但是,如果处理程序是在实现ISynchronizeInvoke
的类(如 winforms 控件)上定义的,则可以在创建它的线程上调用它。以下是我用于引发自动处理此问题的事件的扩展方法:
/// <summary>
/// Fires an event and catches any exceptions raised by an event handler.
/// </summary>
/// <param name="ev">The event handler to raise</param>
/// <param name="sender">The sender of the event.</param>
/// <param name="e">Event arguments for the event.</param>
/// <typeparam name="T">The type of the event args.</typeparam>
public static void Fire<T>(this EventHandler<T> ev, object sender, T e) where T : EventArgs
{
if (ev == null)
{
return;
}
foreach (Delegate del in ev.GetInvocationList())
{
try
{
ISynchronizeInvoke invoke = del.Target as ISynchronizeInvoke;
if (invoke != null && invoke.InvokeRequired)
{
invoke.Invoke(del, new[] { sender, e });
}
else
{
del.DynamicInvoke(sender, e);
}
}
catch (TargetInvocationException ex)
{
ex.InnerException.PreserveStackTrace();
throw ex.InnerException;
}
}
}
/// <summary>
/// Called on a <see cref="TargetInvocationException"/> to preserve the stack trace that generated the inner exception.
/// </summary>
/// <param name="e">The exception to preserve the stack trace of.</param>
public static void PreserveStackTrace(this Exception e)
{
var ctx = new StreamingContext(StreamingContextStates.CrossAppDomain);
var mgr = new ObjectManager(null, ctx);
var si = new SerializationInfo(e.GetType(), new FormatterConverter());
e.GetObjectData(si, ctx);
mgr.RegisterObject(e, 1, si);
mgr.DoFixups();
}
编辑:PreserveStackTrace并不是这个问题的答案的一部分,它只是我使用的解决方案的一部分。我实际上是从SO的另一个答案中得到这种方法的,我不记得确切地是从哪里来的,但它的功劳确实属于其他人。对不起,我不记得是谁了。