首页 文章

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

提问于
浏览
0

我正在修改现有的WinForms项目 . 该项目有UserControl . 此UserControl具有DataSet变量,该变量是从程序的另一部分在不同的线程中设置的 .

我想要做的是根据DataSet动态地向该控件添加另一个控件 .

因此,在加载DataSet之后,我正在调用RefreshChildControl函数并尝试将新的ChildUserControls添加到flowLayoutPanel . 这就是问题开始的地方:) . 我得到“跨线程操作无效:控制'ChildUserControl'从一个线程访问,而不是它在”异常时创建的线程 . 我试图使用if(this.InvokeRequired)和Invoke这个方法,但它没有帮助 . MyUserControl上的InvokeRequired为false .

那么,有没有什么好的方法来执行这样的任务?还是我错过了重要的事情?

编辑:

我试图跳过InvokeRequired测试,只需调用this.FindForm() . 调用此方法 . 我有“在创建窗口句柄之前无法在控件上调用Invoke或BeginInvoke” . 例外 . 顺便说一句,当我用这个控件打开另一个表单时,一切正常 .

2 回答

  • 1

    第一 . 最简单的解决方案是每次都执行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将为您管理所有线程问题 . 它会检查您是从同一个线程还是从另一个线程调用 . 如果相同,它将立即执行您的代码 . 否则它将通过表单的消息循环进行调用 .

  • 2

    如果在构造之后没有立即看到用户控件,则不会在您认为创建它的线程上创建句柄 . 它不是线程父级很重要的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/en-us/library/system.windows.forms.control.createcontrol(v=vs.90).aspx

相关问题