2009-10-27 64 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

相关问题