C# 更改窗体的父线程
我试图找到一种方法,将winform线程的父线程更改回GUI线程。现在我必须从另一个线程创建表单,但是从有引用的主表单访问表单变得不可能 这是我的样品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
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那样显示表单。这将非常有用,因为我有两个窗口要预加载,以便在需要时准备就绪。