我有一些代码如下。这是在“线程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中并创建一个返回异常的委托
答案 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线程等待自己吗?假设这不是你想要的,我在答案中采取了一些“自由”:
有多种选择,但我会展示最简单的选项:
IAsyncResult
存储在本地变量中。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);