找到GUI控件的所有者线程

时间:2010-02-26 14:26:15

标签: .net user-interface multithreading

在.NET应用程序上工作时,我运行的是“跨线程操作无效”异常,只是它似乎发生在正确的线程中。 有没有办法找出哪个线程是创建特定控件的线程?

到目前为止我发现了什么:

'InvokeRequired'操作只告诉IF当前线程是“所有者线程”... 使用Control.Invoke(...)方法上的Reflector有点有趣的时间让我进入了user32.dll中的P / Invoke方法,该方法从窗口句柄获取线程Id:

[DllImport("user32.dll", CharSet=CharSet.Auto, ExactSpelling=true)]
public static extern int GetWindowThreadProcessId(HandleRef hWnd, out int lpdwProcessId);

4 个答案:

答案 0 :(得分:3)

我遇到了同样的问题。即使使用UI线程中的控件,我也会得到该异常。 就我而言,我在创建控件的InvokeRequired之前在后台线程上使用Invoke(或Handle)。它是托盘图标的上下文菜单,某些后台线程必须更改菜单项的值。如果用户从未打开上下文菜单,则从未创建句柄,控件从未绑定到UI线程,并且随之而来的是混乱。发生这种情况时,InvokeRequired总是返回false而Invoke只是在当前线程(不是UI线程)上运行该方法,因此Handle是在后台线程上创建的并且控件永远绑定到该线程,就好像后台线程是它的UI线程一样。当尝试使用UI线程的控件时,抛出了跨线程异常。另一方面,如果用户在运行任何后台线程之前打开了上下文菜单,一切都会正常工作。

解决方案是在启动时从UI线程调用CreateControl()方法,然后任何后台线程都有机会“窃取”控件并破坏线程所有权。

答案 1 :(得分:0)

是否可以在处理程序中创建事件时捕获线程ID,并将其与获取异常时进行比较。这至少会告诉你你是否在同一个线程上。

答案 2 :(得分:0)

Control.BeginInvoke()对我来说总是很好。试试吧。

答案 3 :(得分:0)

尝试使用Spy ++应用程序,它附带VS并显示一个窗口列表(大多数控件是单独的子窗口)以及有关它们的一些信息。