多線程存取WinForm控件

採集器使用的是System.Windows.Forms.WebBrowser, 在constructor裏面添加了DocumentChanged的event handler, 來模擬瀏覽器訪問webmaster的流程, 訪問external-links頁面時便修改constructor傳進來的LinkProfile

在主線程裏是new WebmasterScarper(website, link_profile)之後接着就new LinkProfileTemplate(link_profile)

本來以爲採集器應該走完流程才創建LinkProfileTemplate, 但是發現創建的LinkProfileTemplate是空圖表, Debug時又發現new LinkProfileTemplate() 比 WebBrowser.DocumentChanged的event handler更早執行, 現在纔想起來event handler可能是單獨一個線程?


接着在new LinkProfileTemplate()之間加了循環檢測: 如果link_profile爲空就使進程sleep 1秒, 然後繼續檢測, Debug發現這個循環一直沒有停止, 而且DocumentChanged的event handler一直沒有被調用

這時候想 他們可能是在同一個線程?


接着給採集器單獨建了一個線程執行, browser.Navigate()處出現了異常{"Unable to get the window handle for the 'WebBrowser' control. Windowless ActiveX controls are not supported."},  InnerException是{"Cross-thread operation not valid: Control '' accessed from a thread other than the thread it was created on."} 

確實創建的線程和存取的線程不是同一個線程:

WebmasterScraper scraper = new WebmasterScraper(website, link_profile);

new Thread(scraper.start).Start();

這麼說WinForm的控件不是thread safe


按照這個方法來使用Control.Invoke():

http://www.perceler.com/articles1.php?art=crossthreads1

還是會出現同樣的錯誤

然後把constructor的方法移到了start()中(bad smell..), 出現了另一個異常System.Threading.ThreadStateException: Could not instantiate ActiveX control 'GUID' because the current thread is not in a single-threaded apartment.


最後沒辦法只有把主線程的之後的代碼都放到scraper中了..(powerless..)

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章