问题
I have some code as follows. This is running on "Thread 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
Essentially I am Invoking some methods on a WebBrowser control created on a different thread, "Thread 1".
If the element on the current page loaded in browser does not contain an element "somebtn" or "username", an exception is thrown from "Thread 1".
Is there any way to catch that exception on "Thread 2"? I know I could use try catches within the delegates and have a special delegate that returns some value(like an exception), but is there any way around that options?
Note*: I require the Thread.Sleep as the particular page requires some delay between certain events. If there was some way to combine these events into a single delegate(while retaining some form of non-blocking delay), I think that could work and I would just wrap all of them in single try catch and create a delegate that returns an exception.
回答1:
Although Control.Invoke() executes delegate over UI thread - it is still a synchronous call. Synchronous meaning Invoke will not return until the delegate has completed execution (or exception thrown). You can simply catch the exceptions thrown there.
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
}
回答2:
If you use WebBrowser.Invoke, all delegates are executes on the thread of the User Interface. So everything will be executed on one single thread. So in your question you want the UI thread to wait for itself? Assuming this is not what you want, I took some "freedom" in my answer:
There are multiple options, but I will show the most simple one:
- Start both delegates with BeginInvoke.
- Store the
IAsyncResultof thread1 in a local variable. - Thread2 will do its work.
- Thread2 will do the
EndInvokeof thread1.
Code:
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);
来源:https://stackoverflow.com/questions/16517349/c-sharp-catching-exception-from-invoked-delegate-on-another-thread