2

我有一些代码如下。这是在“线程 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

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

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

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

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

4

2 回答 2

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
}
于 2013-05-14T16:47:16.203 回答
1

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

有多种选择,但我将展示最简单的一种:

  • 使用 BeginInvoke 启动两个代表。
  • IAsyncResultthread1 的值存储在局部变量中。
  • Thread2 将完成它的工作。
  • Thread2 将执行EndInvokethread1。

代码:

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);
于 2013-05-13T08:40:33.433 回答