from:http://www.th7.cn/Program/net/201306/140033.shtmlphp
Windows 窗体中的控件被绑定到特定的线程,不具有线程安全性。所以,若是从另外一个线程调用控件的方法,那么必须使用控件的一个 Invoke 方法来将调用封送到适当的线程。该属性可用于肯定是否必须调用 Invoke 方法,当不知道什么线程拥有控件时这颇有用。html
若是已经建立控件的句柄,则除了 InvokeRequired 属性之外,控件上还有四个能够从任何线程上安全调 用的方法,它们是: Invoke、 BeginInvoke、 EndInvoke 和 CreateGraphics。 在后台线程上建立控件的句柄以前调用 CreateGraphics 可能会致使非法的跨线程调用。 对于全部其余方法调用,当从另外一个线程进行调用时,应使用这些 Invoke 方法之一。安全
若是控件句柄尚不存在,则 InvokeRequired 沿控件的父级链搜索,直到它找到有窗口句柄的控件或窗体为止。 若是找不到合适的句柄, InvokeRequired 方法将返回 false。app
这意味着若是不须要 Invoke(调用发生在同一线程上),或者若是控件是在另外一个线程上建立的但还没有建立控件的句柄,则 InvokeRequired 能够返回 false。函数
若是还没有建立控件的句柄,您就不能简单地在控件上调用属性、方法或事件。这可能致使在后台线程上建立控件的句柄,从而隔离不带消息泵的线程上的控件并使应用程序不稳定。ui
当 InvokeRequired 在后台线程上返回 false 时,您也能够经过检查 IsHandleCreated 的值来避免这种状况。 若是还没有建立控件句柄,您必须等到控件句柄已建立,才能调用 Invoke 或 BeginInvoke。 一般,仅当在应用程序主窗体的构造函数中建立了后台线程时(如同在 Application.Run(new MainForm()) 中),在已经显示窗体或取消 Application.Run 以前,才会发生这种状况。 url
一种解决方案是等到已经建立了窗体的句柄,而后启动后台线程。经过调用 Handle 属性强制建立句柄,或者等待 Load 事件启动后台进程。spa
一种更好的解决方案是使用 SynchronizationContext 返回的 SynchronizationContext,而不是使用控件进行线程间封送处理。——MSDN
线程
关于这方面一个更容易的解释以及例子(参考连接:关于invokeRequired与invoke):code
而关于InvokeRequired与Invoke是个老生常谈的问题,通常标准写法为(图片截图来自:Avoiding InvokeRequired,下同):
这种方式的好处就是能在.NET 1.0+上正常运行,可是若是存在不少控件的话,就会存在这样不少代码(大量定义委托)。
而在.NET 2.0上,能够采用匿名委托和MethodInvoker,简化代码写法,关于
MethodInvokerMSDN上的定义以下:
MethodInvoker 提供一个简单委托,该委托用于调用含 void 参数列表的方法。 在对控件的 Invoke 方法进行调用时或须要一个简单委托又不想本身定义时可使用该委托。
或者更简洁的写法:
而在.NET 3.5+能够利用其特性,代码以下(截图来在:A Generic Method for Cross-thread Winforms Access)
参考资料:
关于invokeRequired与invoke
Avoiding InvokeRequired
A Generic Method for Cross-thread Winforms Access