2013-05-13 93 views
2

我有一些代碼如下。這是在「線程2」C#捕獲在另一個線程上調用委託異常

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 

運行的本質,我就調用在不同的線程創建的WebBrowser控件,「線程1」的一些方法。

如果在瀏覽器中加載的當前頁面上的元素不包含元素「somebtn」或「username」,則會從「線程1」拋出異常。

有沒有辦法在「線程2」上捕獲該異常?我知道我可以在委託中使用try catch,並且有一個特殊的委託來返回一些值(比如異常),但是有沒有辦法繞過這個選項?

注意*:我需要Thread.Sleep,因爲特定頁面在特定事件之間需要一些延遲。如果有一些方法可以將這些事件組合到一個委託中(同時保留某種形式的非阻塞延遲),我認爲這可以工作,我只是將它們全部包裝在單個try catch中,並創建一個返回異常的委託。

+0

如果我走在'WebBrowser'類在MSDN看看(http://msdn.microsoft.com/en-us/library/cc491073.aspx)我沒有看到任何'Invoke'方法。你在使用哪一個? – 2013-05-13 08:25:59

+0

Invoke是所有UI控件的一種方法...它允許從其他線程等更新控件。 – user871289 2013-05-13 08:40:12

+0

如果您的假設爲真,並且您調用了Control.Invoke,則所有委託都將在UI線程上調用。所以...在同一個線程上。那是你要的嗎? – 2013-05-13 08:42:35

回答

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

如果使用WebBrowser.Invoke,則所有委託都在用戶界面的線程上執行。所以一切都將在一個單獨的線程上執行。所以在你的問題中你想讓UI線程等待自己?假設這是不是你想要的,我花了一些「自由」在我的答案:

有多種選擇,但我會告訴最簡單的一個:

  • 開始都代表們的BeginInvoke。
  • 將thread1的IAsyncResult存儲在本地變量中。
  • 線程2將完成其工作。
  • 線程2將執行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);