在没有WinForm控件的主线程上调用方法来调用Invoke或BeginInvoke

Pet*_*lly 5 c# multithreading backgroundworker

我想在后台线程上运行一个操作.当它完成后,我想检查发生的任何错误,并将它们重新抛出我的原始线程.

我正在使用背景工作者.在RunWorkerCompleted事件处理程序中抛出异常会导致未处理的异常 - 如果事件处理程序在后台线程上运行,这是有意义的.如果我有一个winform控件,我可以调用Invoke或BeginInvoke,但我没有在这个对象中使用winform控件,尽管它是一个winform项目.

如何重新抛出backgroundworker中发生的异常?

private void bgw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
    {
        if (e.Error != null)
        {              
            // I want to throw an exception here, without causing an unhandled exception and without being able to call Invoke or BeginInvoke on a WinForm control. 
        }
        else if (e.Cancelled)
        {
           // Do something useful
        }
        else
        {
            if (e.Result != null)
            {
               // Do something with the result
            }
        }
    }
Run Code Online (Sandbox Code Playgroud)

我原以为RunWorkerCompleted事件处理程序将在原始调用线程上运行.也许背景工作者不是我在这种情况下所需要的.

Ter*_*ver 7

将代码注入另一个正在运行的线程是不可能的.甚至操作系统也无法做到这一点.

Control.BeginInvoke的工作原理是将委托引用放入队列,然后使用PostMessage将用户消息发布到UI线程的消息队列中.Application.Run消息循环查找此消息,当它发现它将队列弹出队列并执行它.

关键是没有其他方法可以做你需要的,而不需要对主线程进行编码,以便从另一个线程中寻找某种信号(或消息).

添加

您声明这是一个WinForm应用程序,但您没有控件使用BeginInvoke.

编辑:我提出了一个懒惰的负载而没有考虑它.Control最终可能会在错误的线程上创建.

Application.Run在应用程序的生命周期之前预先创建一个控件.您可以将此用于BeginInvoke.

编辑#3

所以,然后我尝试这一点,以确保它的工作,当然,它没有.你不能简单地创建一个通用的Control,它必须有一个HWND句柄.简单修复:像这样创建它:

invokerControl = new Control();
invokerControl.CreateControl();
Run Code Online (Sandbox Code Playgroud)

这将允许您从它开始BeginInvoke,即使没有要调用的打开Form对象.