2010-03-10 37 views
1

我在處理引發它的其他線程上的事件時遇到問題。但是,處理事件的對象不是UI對象,所以我不能使用Invoke執行委託並自動切換到用於事件處理的UI線程。非UI對象上的跨線程事件處理

的情況如下:我有一個包含多種形式MDI應用程序。每個表單都有自己的控制器類,用於處理耦合表單和外部對象之間的通信。所有表格都是概覽或詳細表格(例如ContactsOverview & ContactDetail)並共享相同的數據。

在發生錯誤的形式出現在類似於嚮導的序列的情況下,說詳細信息表單之後的概述表格。在下面的概覽表格中使用的詳細表格數據發生了變化,在切換到概覽表格之前,需要在這些表格中反映出這些變化。從詳細信息表單中引發事件,並由控制器爲完成必要的UI元素更新的概覽表單處理。

現在詳表的更改數據的保存可能需要一段時間,因此是必要的UI會保持應用程序的響應和其他部分仍可使用。這就是後臺工作者開始處理這個問題的原因。數據保存後,事件在後臺線程中引發。概述的控制器處理這個,但是當UI需要更新時,當然存在跨線程異常。

所以我需要的是一種方法來提高UI線程上的事件,但由於處理不UI元素上發生的沒有辦法來自動切換使用調用線程。

從網絡上搜索,我發現這是使用生產者/消費者模式的一個可能的解決方案。但是,據我所知,這需要每個控制器在單獨的線程中監聽一系列事件。由於它是一個MDI應用程序,理論上可以有任何形式的控制器,我不想啓動那麼多的線程。

歡迎任何建議。如果有一種方法可以避免使用背景工作者,那麼這也是一個合適的解決方案。

感謝您的閱讀,

凱文

回答

1

您可以使用SynchronizationContext,特別是SynchronizationContext.Current將消息發佈到主同步上下文(這是GUI應用程序的主線程)。

不幸的是我不夠了解類及其用法說這是一個明確的解決方案。特別是,如果您不需要主線程來處理您的事件,而是需要特定的線程,我不知道該怎麼辦。

也許WindowsFormsSynchronizationContext類可以幫助你,它有一個公共無參數的構造函數,我想它可能會將它與當前線程相關聯,所以如果你從擁有控制器的線程構造該對象並給它到後臺線程代碼,它可能工作。

+0

謝謝,我會研究它。 – kwe 2010-03-10 09:48:35

+0

正是我想建議... – 2010-03-10 09:48:39

+0

在閱讀這篇有用的文章 - http://msmvps.com/blogs/manoj/archive/2005/11/03/74120.aspx - 我很確定這種方法將能夠解決我的問題。根據我的理解,您可以使用SynchronizationContext來保存對調用線程的引用,並且在後臺線程中的處理完成後,可以使用SynchronizationContext中的引用在調用線程上啓動事件。我已經在一個快速演示項目中測試過它,它可以工作。再次感謝! – kwe 2010-03-10 10:31:20

0

您可以對背景objec的UI元素訂閱的事件。在事件處理程序(訂閱的 - 所以它是窗口代碼的一部分),你可以然後調用。這是我解決這個問題的方法。

+0

問題是UI元素沒有訂閱事件,UI元素的控制器是,它只是一個普通的c#類,並沒有invoke方法。 – kwe 2010-03-10 09:38:06

+0

那麼......在這種情況下,我會說控制器完全脫離UI元素不起作用,或者;) 也許控制器應該得到一個指向表單的指針,所以它可以調用... – TomTom 2010-03-10 10:12:16

+0

那麼應用程序是在第三方框架上開發的,並且改變關於UI和控制器之間關係的任何事情都會導致代碼更改的海嘯。但它會爲我們節省很多麻煩,如果它像你的建議:) – kwe 2010-03-10 10:47:51

0

你可以試試這個flag但我不認爲這是最好的想法,只是一個解決辦法。

您也可以嘗試在非圖形線程中實例化發佈對象,這可能會解決您的問題。

還有一件事,你不能讓你的UI組件處理RunWorkerCompleted(與indirections)?

+0

您的意思是從UI元素啓動後臺工作器,然後通過RunWorkerCompleted中的UI元素訪問UI線程? – kwe 2010-03-10 09:56:04

+0

劃傷第一條評論,我明白你的意思了。問題在於數據的保存會自動觸發事件的發生,並且分離該部分將是相當多的工作,而不是使用我接受的答案SynchronizationContext。但它仍然是一個可行的解決方案。謝謝。 – kwe 2010-03-10 10:45:01