【问题标题】:Events raised by BackgroundWorker not executed on expected threadBackgroundWorker 引发的事件未在预期线程上执行
【发布时间】:2010-03-22 06:31:38
【问题描述】:

一个 winforms 对话框正在使用 BackgroundWorker 执行一些异步操作,并取得了巨大的成功。有时,后台工作人员正在运行的异步进程需要向 winforms 应用程序引发事件以供用户响应(询问用户是否希望取消的消息),其响应在事件的 CancelEventArgs 类型中捕获.

作为线程的实现,我本来希望工作人员的 RaiseEvent 会触发,然后工作人员会继续,因此需要我暂停工作人员,直到收到响应。然而,worker 会等待由 raise 事件执行的代码完成。

似乎我通过事件调用调用的方法实际上是在后台工作人员使用的工作线程上,我很惊讶,因为我希望在主窗体运行的主线程上看到它。同样令人惊讶的是,没有抛出跨线程异常。

有人能解释一下为什么这不是我所期望的吗?

【问题讨论】:

    标签: .net vb.net multithreading backgroundworker


    【解决方案1】:

    BackgroundWorker 将在 UI 线程上引发其 ProgressChanged 事件和 RunWorkerCompleted 事件(更准确地说,它将使用当前建立的 SynchronizationContext 将它们发布到线程。)

    但它不会简单地使您能够在 UI 线程上引发任意事件。为此,您应该访问 SynchronizationContext.Current 并使用 Post 方法。

    【讨论】:

    • 谢谢乔希,看起来不错,我明天去看看。当我从该事件调用 Windows.Forms.Messagebox.Show 时没有引发跨线程异常,我仍然感到惊讶,因为它仍在后台线程上。
    • 没有“UI 线程”之类的东西,只是碰巧有一个线程,您只能从中运行 UI 内容。任何线程都可以调用诸如 MessageBox 之类的 UI 内容或创建和显示 WinForms。同样,您的工作线程并不真正知道它正在异步运行,因此就像正常运行一样引发事件。
    • 技术上 Chris 是正确的,但是从当前没有消息循环的线程调用 MessageBox.Show 将导致创建一个(否则 MessageBox 将不起作用),所以我同意它会很好如果以 Windows 窗体控件的工作方式检查非法跨线程访问。
    • 顺便说一句,当您从后台线程调用 MessageBox 时,您通常可以立即分辨出来,因为它不会像其他控件那样在视觉上样式化。这些按钮将是 XP 之前的“扁平”样式。
    • 嗨 Josh,从上面的 cmets 中我了解到 MessageBox.Show 永远不会引发跨线程异常。如果这是正确的,您是否通过以我当前的方式显示消息框看到任何不良副作用。这将避免使用 post 方法并锁定后台线程,直到通过 CancelEventArgs 从消息框返回响应。当然,如果需要比消息框更丰富的 UI,那么我们需要做所有这些。
    猜你喜欢
    • 2020-01-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-09-23
    相关资源
    最近更新 更多