C#从另一个线程上的Invoked Delegate捕获异常

时间:2013-05-13 08:03:55

标签: c# multithreading delegates invoke

我有一些代码如下。这是在“线程2”上运行的

WebBrowser browser = this.webBrowser    
browser.Invoke(new MethodInvoker(delegate { browser.Document.GetElementById("somebutton").InvokeMember("click"); }));
Thread.Sleep(500);
browser.Invoke(new MethodInvoker(delegate { browser.Document.GetElementById("username").SetAttribute("value", username); }));
//folowed by several more similar statments

基本上我在一个不同的线程“Thread 1”上创建的WebBrowser控件上调用一些方法。

如果浏览器中加载的当前页面上的元素不包含元素“somebtn”或“username”,则会从“Thread 1”抛出异常。

有没有办法在“线程2”上捕获该异常?我知道我可以在委托中使用try catch并且有一个返回一些值的特殊委托(比如异常),但有没有办法解决这些选项?

注意*:我需要Thread.Sleep,因为特定页面需要在某些事件之间有一些延迟。如果有某种方法可以将这些事件组合到一个委托中(同时保留某种形式的非阻塞延迟),我认为这可以工作,我只需将所有这些事件包装在单个try catch中并创建一个返回异常的委托

2 个答案:

答案 0 :(得分:2)

虽然Control.Invoke()通过UI线程执行委托 - 但它仍然是同步调用。在委托完成执行(或抛出异常)之前,同步意义Invoke将不会返回。你可以简单地捕捉那里抛出的异常。

WebBrowser browser = this.webBrowser;
try {    
    browser.Invoke(new MethodInvoker(delegate { browser.Document.GetElementById("somebutton").InvokeMember("click"); }));
    Thread.Sleep(500);
    browser.Invoke(new MethodInvoker(delegate { browser.Document.GetElementById("username").SetAttribute("value", username); }));
} catch(Exception e) 
{
    //catch in Thread 2
}

答案 1 :(得分:1)

如果使用WebBrowser.Invoke,则所有委托都在用户界面的线程上执行。所以一切都将在一个线程上执行。那么在您的问题中,您希望UI线程等待自己吗?假设这不是你想要的,我在答案中采取了一些“自由”:

有多种选择,但我会展示最简单的选项:

  • 使用BeginInvoke启动两个委托。
  • 将thread1的IAsyncResult存储在本地变量中。
  • Thread2将完成它的工作。
  • Thread2将执行thread1的EndInvoke

代码:

WebBrowser browser = this.webBrowser;
MethodInvoker thread1 = delegate
{
    browser.Document.GetElementById("somebutton").InvokeMember("click");
};
IAsyncResult result1 = thread1.BeginInvoke(null, null);
Thread.Sleep(500);
MethodInvoker thread2 = delegate
{
    browser.Document.GetElementById("username").SetAttribute("value", username);
    try
    {
        thread1.EndInvoke(result1);
    }
    catch (Exception ex)
    {
        // Exception of thread1.
    }
};
thread2.BeginInvoke(null, null);