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

本文关键字:创建 控件 线程 UI 确保 | 更新日期: 2023-09-27 18:16:09

我正在修改现有的WinForms项目。项目有UserControl。这个UserControl有一个数据集变量,它是在不同线程的程序的另一部分设置的。

我想做的是动态地添加另一个控件到这个控件,这取决于数据集。

所以,在数据集加载后,我调用RefreshChildControl函数并尝试将我的新ChildUserControls添加到flowLayoutPanel。这就是问题的开始:)。我得到"跨线程操作无效:控制'ChildUserControl'从线程以外的线程访问它是创建在"异常。我试图使用if(this. invokerrequied)和Invoke这个方法,但它没有帮助。MyUserControl上的invokerrequirequired为false

那么,有没有什么好的方法来完成这样的任务呢?还是我错过了什么重要的东西?

编辑:

我试着跳过invokerrequiredtest,只调用this.FindForm()。调用此方法。我有"调用或BeginInvoke不能在控件上调用,直到窗口句柄被创建。"异常。顺便说一下,当我用这个控件打开另一个表单时,一切都很好。

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

第一。最简单的解决方案是每次都执行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。如果控件不可见,则不会创建句柄。

现在你可以让另一个线程更新你的用户控件,即使用户控件不可见。

 uc.BeginInvoke((Action)(() => uc.Text = "ha ha"));

如果你省略dummy = uc.Handle行,你将得到一个异常,你不能在一个没有句柄的控件上调用BeginInvoke。

http://msdn.microsoft.com/en-us/library/system.windows.forms.control.createcontrol (v =应用程序). aspx