2009-10-27 97 views
6

我正在處理一個大型應用程序(獲得跨線程異常)時遇到了一些線程問題。有沒有辦法找到創建特定控件的線程名稱/ ID?有沒有辦法找到控件的所有者線程?

當我嘗試向控件的控件集合添加新控件時發生此錯誤。我不能真正創建一個小的,可重複的樣本,所以我會盡我所能地描述它。

我有一個坐在窗體上的主控件,稱之爲_mainControl。在它的構造我實例化另一個控制的一個實例,像

ChildControl _childControl = new ChildControl(); 

現在_childControl存在,但我不把它添加到_mainControls最愛。

最後,_mainControl接收到一個事件通知,我應該添加該控件。在事件處理我檢查this.InvokeRequired,如果是,我調用處理程序,類似如下:

AddControlEventHander(...) 
{ 
    if(InvokeRequired) 
    { 
     BeginInvoke(new MethodInvoker(AddControlEventHander); 
     return; 
    } 
    Controls.Add(_childControl); 
} 

唯一的例外是在Controls.Add被(「跨線程操作無效,始終拋出:控制'_item'從其創建線程以外的線程訪問「)。

現在,我不明白的是這是如何可能的。我在創建_mainControl的同一個線程上創建_childControl。當我在調試時查看線程窗口時,當我調用Control.Add時,當前線程名稱/ ID與添加_childControl時相同。但是,最讓我困惑的是來自_mainControl的以下調用:

InvokeReuqired == false; 
_childControl.InvokeRequired == false; 
_childControl._item.InvokeRequired == true; //I made _item public just to try this and it returns true! 

這怎麼可能?是否有可能在一個線程上創建_childControl,而在另一個線程上創建子控件?正常情況下,_childControl的所有子項都是在初始化過程中創建的。

如果任何人有任何提示/建議可能會發生什麼,請讓我知道。

謝謝。

編輯:

如果有人有興趣,我發現發生了什麼事。我很好奇如何在一個線程上創建一個控件,並且它是在另一個線程上創建的子類,即使InitializeComponent都是在同一個線程上完成的。因此,我使用類似於Charles在下面提出的代碼來找出創建哪個線程。一旦我知道了,我至少知道應該關注哪個線程。然後我打破了兒童控制的OnHandleCreated事件,發現了這個問題。

我不知道的一件事是控件的句柄是在控件第一次變得可見時創建的,而不是在創建時創建的。所以一個沒有控制權的線程試圖將它的可見性設置爲true。所以我添加了一張支票,看看InvokeRequired是否可以實現。然而,我真的沒有想到的是,調用InvokeRequired將創建控件的句柄,如果它尚未創建!這實際上導致控制被創建在錯誤的線程上,並且總是爲InvokeRequired返回false。我通過觸摸控件的Handle屬性來解決此問題,以便在調用InvokeRequired之前創建該屬性。

感謝您的幫助球員:)

+0

感謝您的提示。我同樣發現無害的'if(control.Handle!= null)...'實際上創建了該線程上的控件! – 2013-06-11 21:48:39

+0

在這裏看到我的答案http://stackoverflow.com/questions/8331144/ensuring-that-c​​hild-controls-are-created-in-main-ui-thread/17054689#17054689 – 2013-06-11 22:09:43

回答

3

要獲得控制所有者線程,試試這個:

private Thread GetControlOwnerThread(Control ctrl) 
{ 
    if (ctrl.InvokeRequired) 
     ctrl.BeginInvoke(
      new Action<Control>(GetControlOwnerThread), 
      new object[] {ctrl}); 
    else 
     return System.Threading.Thread.CurrentThread; 
} 

燦子控件是從父(容器控件)不同的線程?是的,這一切都取決於構建控件時正在運行的線程(新增)

您總是必須檢查InvokeRequired ...因爲您永遠不知道可能調用哪個線程進入正在編碼的方法。 ..是否需要爲每個子控件分別檢查InvokeRequired,取決於您確定所有控件是否在同一個線程上創建。如果所有控件都是在創建表單時創建的,則在相同的初始化例程中,則可能安全地假設它們全部創建在同一個線程上

+0

嗯。那麼,當您試圖查看控件是否需要InvokeRequired時,需要進行哪種檢查?你是否總是需要檢查控件及其所有孩子的InvokeRequired? – Flack 2009-10-27 23:57:50

+0

是的,你總是要檢查InvokeRequired ...因爲你永遠不知道什麼線程可能會調用你正在編寫的方法......是否需要單獨檢查每個子控件的InvokeRequired,取決於你是多麼確定這些控件是在相同的線程上創建的或不是。如果所有控件都是在創建表單時創建的,則在相同的初始化例程中,則可能很安全地假設它們都創建在同一個線程上。 – 2009-10-28 00:03:05

+0

這對我來說似乎很奇怪。從我可以告訴,_childControl和它的所有孩子看起來像他們是在同一個線程上創建的。此外,如果_childControls子項以某種方式在不同的線程上創建,我看不到如何調用_mainControl的Controls.Add,因爲由於交叉線程而創建_childControl句柄時失敗。我因_childControl或其子女而失敗。我不明白這是可能的。我會重新審視它並做一些重構。也許它會消失:) – Flack 2009-10-28 02:23:33

相關問題