C# 更改窗体的父线程

C# 更改窗体的父线程,c#,winforms,task-parallel-library,.net-4.6,C#,Winforms,Task Parallel Library,.net 4.6,我试图找到一种方法,将winform线程的父线程更改回GUI线程。现在我必须从另一个线程创建表单,但是从有引用的主表单访问表单变得不可能 这是我的样品 public partial class MainForm : Form { // local instance of the sub form private ViewForm SubForm { get; set;} = null; public MainForm() { Initialize

我试图找到一种方法,将winform线程的父线程更改回GUI线程。现在我必须从另一个线程创建表单,但是从有引用的主表单访问表单变得不可能

这是我的样品

public partial class MainForm : Form
{
    // local instance of the sub form
    private ViewForm SubForm { get; set;} = null;

    public MainForm()
    {
        InitializeComponent();

        Task.Run(() =>
        {
            // set the sub form             
            SubForm = new ViewForm();
        }

        // call the rest of the initialization of main form
        InitializeCustomControls();
    }

    private void OpenViewWindow_Click(object sender, EventArgs e)
    {
        // if the window is instanciated
        if (SubForm != null)
        {
            SubForm.Show();                
        }
    }        
}
ViewForm
窗口不是
Form
对象。这是一个自定义的第三方窗口。它有很多控件和模板与主题混合。对一个新的空构造函数的唯一调用可能需要长达7秒的时间,因此我需要在另一个线程上创建它,同时继续加载我的主窗口

现在我可以调用窗口中的任何方法,除了
.Show()
,由于线程创建限制,该方法总是失败。我希望不要把线程创建为一个无休止的运行线程,它将等待并读取一些对象,告诉他何时显示和隐藏窗口

错误是
.Show()
错误:

跨线程操作无效:从创建控件的线程以外的线程访问控件“ViewForm”。

我确实尝试了以下操作,但仍然冻结了我的界面:

Task.Run(() =>
{
    // set the sub form   
    this.Invoke(new MethodInvoker(delegate
    {
        SubForm = new ViewForm();
    }));
}

我想要的是一个类似于fire and forget GUI对象实例化的东西。

这里有一个使用
BackGroundWorker的解决方案:

public partial class MainForm : Form
{
    // local instance of the sub form
    private ViewForm SubForm { get; set;} = null;

    public MainForm()
    {
        InitializeComponent();
        backGroundWorker1.RunWorkerAsync();
        InitializeCustomControls();
    }

    private void OpenViewWindow_Click(object sender, EventArgs e)
    {
        // if the window is instanciated
        if (SubForm != null)
        {
            SubForm.Show();                
        }
    }

    private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
    {
        SubForm = new ViewForm();
    }
}

测试创建两个表单,与示例中的表单非常相似的
main表单
,以及带有
Threading.Sleep(10000)
子视图
表单,在构造函数上。

我没有阅读你的全部帖子,但是你问题的标题和第一句话很突出。答案是:你不应该在主线程之外的任何东西上运行UI代码。这是UI编程的黄金法则。因此,如果你遵循这一点,那么你就不会有这个问题。如果你有一个第三方表单在启动时将UI线程冻结7秒,那么它就有一个主要的bug。要么不要使用那个有缺陷的第三方表单,要么让他们修复这个bug。@rory.ap虽然这是我的第一反应,但有缺陷的代码显然在第三方代码中,所以OP不能强制执行这个规则。
if(SubForm!=null){SubForm.BeginInvoke(new MethodInvoker(delegate{SubForm.Show());}
只需要使用次线程上运行的控件的调用。看看是否可以使用。它是一个线程池,用于处理WinForms,自动处理UI元素上的跨线程操作,因此您不必涉及调用内容。我认为它可以处理您的问题,但我不确定。这是一个完美的解决方案我不需要像@Gusman-trick那样显示表单。这将非常有用,因为我有两个窗口要预加载,以便在需要时准备就绪。