[英]Ensuring that child controls are created in main UI thread
我正在修改现有的WinForms项目。 该项目具有UserControl。 该UserControl具有DataSet变量,该变量是从程序的另一部分在不同线程中设置的。
我要做的是根据数据集向该控件动态添加另一个控件。
因此,在加载DataSet之后,我将调用RefreshChildControl函数,并尝试将新的ChildUserControls添加到flowLayoutPanel中。 这就是问题开始的地方:)。 我收到“跨线程操作无效:从不是在其上创建线程的线程访问的控件'ChildUserControl'”异常。 我尝试使用if(this.InvokeRequired)并调用此方法,但无济于事。 MyUserControl上的InvokeRequired为false。
那么,有没有执行这种任务的好方法呢? 还是我错过了重要的事情?
编辑:
我试图跳过InvokeRequired测试,仅对此方法调用this.FindForm()。Invoke。 我得到“在创建窗口句柄之前,无法在控件上调用Invoke或BeginInvoke”。 例外。 而且,顺便说一下,当我使用此控件打开另一个表单时,一切正常。
第一。 最简单的解决方案是每次执行Invoke。 不会有坏事发生。 其次,使用SynchronizationContext。
using System.Threading;
public class YourForm
{
SynchronizationContext sync;
public YourForm()
{
sync = SynchronizationContext.Current;
// Any time you need to update controls, call it like this:
sync.Send(UpdateControls);
}
public void UpdateControls()
{
// Access your controls.
}
}
SynchronizationContext将为您管理所有线程问题。 它检查您是从同一个线程还是从另一个线程进行调用。 如果相同,它将立即执行您的代码。 否则,它将通过表单的消息循环进行调用。
如果您的用户控件在构造之后不立即可见,则不会在您认为创建该控件的线程上创建该句柄。 不是C#对象的父线程很重要,而是Windows Handle对象的父线程很重要。
若要强制在您认为创建该线程的线程上立即创建控件,请读出该control.Handle
的句柄,该句柄将强制该控件实际完成并分配一个句柄。
MyUserControl uc = new MyUserControl(); // the handle is not created here
uc.Visible = false;
IntPtr dummy = uc.Handle; // The control is immediately given a real handle
您也可以尝试使用uc.CreateControl摆弄,但是如果控件不可见,则不会创建该句柄。
现在,即使用户控件不可见,您也可以让另一个线程更新您的用户控件。
uc.BeginInvoke((Action)(() => uc.Text = "ha ha"));
如果忽略了dummy = uc.Handle
行,则会出现一个异常,即您无法在没有句柄的控件上调用BeginInvoke。
http://msdn.microsoft.com/zh-CN/library/system.windows.forms.control.createcontrol(v=vs.90).aspx
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.