简体   繁体   English

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

[英]Ensuring that child controls are created in main UI thread

I'm modifying existing WinForms project. 我正在修改现有的WinForms项目。 The project has UserControl. 该项目具有UserControl。 This UserControl has DataSet variable which is set from another part of the program in different thread. 该UserControl具有DataSet变量,该变量是从程序的另一部分在不同线程中设置的。

What I want to do is to dynamically add another controls to this control depending on the DataSet. 我要做的是根据数据集向该控件动态添加另一个控件。

So, after DataSet is loaded, I'm calling RefreshChildControl function and trying to add my new ChildUserControls to flowLayoutPanel. 因此,在加载DataSet之后,我将调用RefreshChildControl函数,并尝试将新的ChildUserControls添加到flowLayoutPanel中。 And that's where the problems begin:). 这就是问题开始的地方:)。 I get the "Cross-thread operation not valid: Control 'ChildUserControl' accessed from a thread other than the thread it was created on" exception. 我收到“跨线程操作无效:从不是在其上创建线程的线程访问的控件'ChildUserControl'”异常。 I tried to use if(this.InvokeRequired) and Invoke this method, but it does not help. 我尝试使用if(this.InvokeRequired)并调用此方法,但无济于事。 InvokeRequired on MyUserControl is false. MyUserControl上的InvokeRequired为false。

So, is there any good way of performing such task? 那么,有没有执行这种任务的好方法呢? Or am I missing something important? 还是我错过了重要的事情?

EDIT: 编辑:

I tried to skip InvokeRequired test and just call this.FindForm().Invoke on this method. 我试图跳过InvokeRequired测试,仅对此方法调用this.FindForm()。Invoke。 I've got "Invoke or BeginInvoke cannot be called on a control until the window handle has been created." 我得到“在创建窗口句柄之前,无法在控件上调用Invoke或BeginInvoke”。 exception. 例外。 And, by the way, when I open another form with this control everything worked fine. 而且,顺便说一下,当我使用此控件打开另一个表单时,一切正常。

First. 第一。 The simplest solution is to perform Invoke everytime. 最简单的解决方案是每次执行Invoke。 Nothing bad will happen. 不会有坏事发生。 Second, use SynchronizationContext. 其次,使用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 will manage all threading issues for you. SynchronizationContext将为您管理所有线程问题。 It checks, whether you call from the same or from the other thread. 它检查您是从同一个线程还是从另一个线程进行调用。 If from same it will just immediately execute your code. 如果相同,它将立即执行您的代码。 Otherwise it will do Invoke through form's message loop. 否则,它将通过表单的消息循环进行调用。

If your user control is not immediately visible after you construct it, the handle will not be created on the thread that you think it is created on. 如果您的用户控件在构造之后不立即可见,则不会在您认为创建该控件的线程上创建该句柄。 It's not the C# object whose thread parent is important, it is the Windows Handle object whose parent is important. 不是C#对象的父线程很重要,而是Windows Handle对象的父线程很重要。

To force a control to be immediately created on the thread that you thought you created it on, then read out the control.Handle which will force the control to actually be made and assigned a 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

You can also try to fiddle around with uc.CreateControl, but this won't create the handle if the control is not visible. 您也可以尝试使用uc.CreateControl摆弄,但是如果控件不可见,则不会创建该句柄。

Now you can have another thread update your user control even if the user control is not visible. 现在,即使用户控件不可见,您也可以让另一个线程更新您的用户控件。

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

If you leave out the dummy = uc.Handle line, you will get an exception that you can't call BeginInvoke on a control that does not have a handle. 如果忽略了dummy = uc.Handle行,则会出现一个异常,即您无法在没有句柄的控件上调用BeginInvoke。

http://msdn.microsoft.com/en-us/library/system.windows.forms.control.createcontrol(v=vs.90).aspx 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