我正在处理一个大型应用程序的线程问题(出现了跨线程异常)。有没有办法找到特定控件创建的线程名称/ID?
当我尝试将新控件添加到我的控件集合时,就会出现错误。我无法创建一个小的、可重现的示例,因此我会尽可能描述它。
我有一个主控件,它位于一个窗体上,称之为_mainControl。在它的构造函数中,我实例化另一个控件的实例,类似于:
ChildControl _childControl = new ChildControl();
现在_childControl已经存在,但我还没有将它添加到_mainControls集合中。
最终,_mainControl会收到一个事件通知,告诉我应该添加这个控件。在事件处理程序中,我会检查是否需要使用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之前创建它。
谢谢大家的帮助 :)
if (control.Handle != null) ...
实际上在该线程上创建了控件! - Mark Lakata