我确信这有一个好的(或至少是体面的)原因.它是什么?
我认为这是一个很好的问题 - 我认为需要一个更好的答案.
当然唯一的原因是框架中的某些东西不是非常线程安全的.
System.Windows.Forms中的每个控件上几乎每个实例成员都有"东西".
System.Windows.Forms中许多控件的MSDN文档,如果不是全部,说 "此类型的任何公共静态(在Visual Basic中共享)成员都是线程安全的.任何实例成员都不保证是线程安全的."
这意味着实例成员TextBox.Text {get; set;}
不是可重入的.
使每个实例成员都是线程安全的,可能会引入大量应用程序不需要的开销.相反,.Net框架的设计者决定,并且我认为正确的是,应该将来自多个线程的对表单控件的访问同步的负担放在程序员身上.
[编辑]
虽然这个问题只是问"为什么"这里是链接到一篇解释"如何"的文章:
如何:在MSDN上对Windows窗体控件进行线程安全调用
http://msdn.microsoft.com/en-us/library/ms171728.aspx
因为你可以很容易地陷入僵局(以及其他问题).
例如,您的辅助线程可能正在尝试更新UI控件,但UI控件将等待由辅助线程锁定的资源被释放,因此两个线程最终都会等待彼此完成.正如其他人所评论的那样,这种情况并非UI代码所独有,而是特别常见.
在其他语言(如C++)中,您可以自由尝试执行此操作(没有像在WinForms中那样抛出异常),但是如果发生死锁,您的应用程序可能会冻结并停止响应.
顺便提一下,您可以轻松告诉UI线程您要更新控件,只需创建一个委托,然后在该控件上调用(异步)BeginInvoke方法,将其传递给您的委托.例如
myControl.BeginInvoke(myControl.UpdateFunction);
这相当于从工作线程执行C++/MFC PostMessage
虽然听起来合理,但约翰的回答并不正确.事实上即使使用Invoke,你仍然不安全,不会遇到死锁情况.处理使用Invoke在后台线程上触发的事件时,甚至可能导致此问题.
真正的原因更多地与竞争条件有关,并在古代的Win32时代奠定了基础.我无法解释这里的细节,关键字是消息泵,WM_PAINT事件以及"SEND"和"POST"之间的细微差别.
更多信息可以在这里和这里找到.