繁体   English   中英

确保在主UI线程中创建子控件

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM