我正在修改现有的WinForms项目 . 该项目有UserControl . 此UserControl具有DataSet变量,该变量是从程序的另一部分在不同的线程中设置的 .
我想要做的是根据DataSet动态地向该控件添加另一个控件 .
因此,在加载DataSet之后,我正在调用RefreshChildControl函数并尝试将新的ChildUserControls添加到flowLayoutPanel . 这就是问题开始的地方:) . 我得到“跨线程操作无效:控制'ChildUserControl'从一个线程访问,而不是它在”异常时创建的线程 . 我试图使用if(this.InvokeRequired)和Invoke这个方法,但它没有帮助 . MyUserControl上的InvokeRequired为false .
那么,有没有什么好的方法来执行这样的任务?还是我错过了重要的事情?
编辑:
我试图跳过InvokeRequired测试,只需调用this.FindForm() . 调用此方法 . 我有“在创建窗口句柄之前无法在控件上调用Invoke或BeginInvoke” . 例外 . 顺便说一句,当我用这个控件打开另一个表单时,一切正常 .
2 回答
第一 . 最简单的解决方案是每次都执行Invoke . 什么都不会发生 . 其次,使用SynchronizationContext .
SynchronizationContext将为您管理所有线程问题 . 它会检查您是从同一个线程还是从另一个线程调用 . 如果相同,它将立即执行您的代码 . 否则它将通过表单的消息循环进行调用 .
如果在构造之后没有立即看到用户控件,则不会在您认为创建它的线程上创建句柄 . 它不是线程父级很重要的C#对象,它是父级很重要的Windows Handle对象 .
要强制在您认为创建它的线程上立即创建控件,然后读出
control.Handle
,这将强制控件实际生成并分配一个句柄 .您也可以尝试使用uc.CreateControl,但如果控件不可见,则不会创建句柄 .
现在,即使用户控件不可见,您也可以让另一个线程更新您的用户控件 .
如果省略
dummy = uc.Handle
行,您将得到一个异常,您无法在没有句柄的控件上调用BeginInvoke .http://msdn.microsoft.com/en-us/library/system.windows.forms.control.createcontrol(v=vs.90).aspx