在.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);
答案 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并显示一个窗口列表(大多数控件是单独的子窗口)以及有关它们的一些信息。