C# 交叉线程集控制

C# 交叉线程集控制,c#,multithreading,C#,Multithreading,我想设置您正在使用另一个线程上创建的控件的线程 在不同线程上创建的控件:PictureBox PBox,SplitContainer\u sc enter code here class Class1 { public Class1(SplitContainer _sc,PictureBox PBox) { SetPanel(_sc,PBox); } delegate void SetPanelDele(SplitContainer _sc,

我想设置您正在使用另一个线程上创建的控件的线程

在不同线程上创建的控件:
PictureBox PBox
SplitContainer\u sc

enter code here
class Class1
{
    public Class1(SplitContainer _sc,PictureBox PBox)
    {
        SetPanel(_sc,PBox);
    }


    delegate void SetPanelDele(SplitContainer _sc, PictureBox pb);
    void SetPanel(SplitContainer _sc, PictureBox pb)
    {
        if (pb.InvokeRequired && _sc.InvokeRequired)
        {
            pb.Invoke(new SetPanelDele(SetPanel), new object[] { _sc, pb });
        }
        else
        {
            pb.Parent = _sc.Panel2; // here
        }
    }
 }   

请注意,如果
pb.invokererequired!=_sc.invokererequired
然后您遇到了一个严重问题,这两个控件必须在UI线程上有效

回答您的问题,然后它是不,您不能使用在另一个线程中创建的控件,除非您确保未在该线程上创建句柄

简而言之(让我简化一下):所有控件都必须从UI线程创建和访问。没有例外

稍长一点:可以从任何线程创建实例,但句柄必须在UI线程中创建。这意味着sc和pb可以在两个不同的线程中创建,然后合并到UI线程中的UI中,但您必须确保不要调用任何方法或设置任何会导致创建句柄的属性

它可以做,但它非常脆弱。您可以做的是提供一个工厂方法,您将在适当的线程上调用该方法:

static void AddControl(Control control, Func<Control> factory)
{
    if (control.InvokeRequired)
    {
        control.BeginInvoke(
            new Action<Control, Func<Control>>(AddToControls), control, factory);
    }
    else
    {
        control.Controls.Add(factory());
    }
}
请注意,工厂方法将捕获变量,如果您使用调用线程访问共享资源,则可能需要一些同步。我使用了
BeginInvoke()
而不是
Invoke()
来阻止调用线程,因为在WinForms中我们不需要调用
EndInvoke()



旁注:与您的问题无关,您应该坚持命名约定,现在您有了
\u sc
(函数参数的前缀为下划线)、
PBox
(函数参数的标题大小写)、
pb
(函数参数的大小写都是小写或驼峰大小写)。这有点让人困惑,通常参数和局部变量都是不固定的驼峰大小写标识符。

那么问题是什么呢?您可能应该检查
这个。invokererequired
,而不是
pb。invokererequired
谢谢您,但我不能用它来询问示例。
添加到控件(\u sc,)
// I'm in another non UI thread...
AddControl(splitContainer, () =>
{
    // Just an example...
    return new PictureBox
    {
        Size = new Size(40, 40),
        Image = LoadImageFromFile()
    };
});