C# 窗体显示不使用线程
我正在创建一个应用程序,其中它启动一个FormSelect(),要求用户在列表中选择一项,当用户按下“选择”按钮时,它将创建一个新的MainForm()实例,隐藏FormSelect并显示MainForm,但它不工作,我所做的所有测试都出现异常 以下是一些代码:C# 窗体显示不使用线程,c#,.net,winforms,C#,.net,Winforms,我正在创建一个应用程序,其中它启动一个FormSelect(),要求用户在列表中选择一项,当用户按下“选择”按钮时,它将创建一个新的MainForm()实例,隐藏FormSelect并显示MainForm,但它不工作,我所做的所有测试都出现异常 以下是一些代码: static class Program { public static MainForm mainForm; /// <summary> /// The main entry
static class Program {
public static MainForm mainForm;
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main() {
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new FormSelect());
}
}
正如您在上面看到的,我正在使用一个任务来启动MainForm,这样它就不会冻结我的UI和“加载spiner”
但是当它尝试使用.Show()时,我得到了一个跨线程异常,因此我尝试使用以下方法调用该操作:
this.Invoke(new MethodInvoker(delegate () { Program.mainForm.Show(); }));
但是使用上面的方法,我得到一个例外,说:
System.Windows.Forms.dll中发生“System.ComponentModel.Win32Exception”类型的异常,但未在用户代码中处理
其他信息:创建窗口句柄时出错
如果我删除startMatInfo方法中的“await Task.Run()…”,一切正常,但它会完全阻塞FormSelect UI
我怎样才能避免这个问题?谢谢大家! 你不能那样做 如果没有一个可靠地再现问题的好方法,就不可能确定您的场景的最佳解决方案是什么。但UI对象必须创建并仅在UI线程中使用。无法在工作线程中创建
MainForm
实例
因为您的代码示例不完整,所以不清楚您为什么要首先使用Task.Run()
创建MainForm
实例。代码所做的只是调用构造函数,而构造函数无论如何都不应该是耗时的操作
如果您需要执行一些耗时的初始化,那么应该将其从MainForm
类中抽象出来,并将其放入其他类中,在完全初始化后可以传递给MainForm
。然后,您可以通过调用Task.Run()
(但仍然不在构造函数中…创建对象,然后如果需要异步调用初始化该对象的方法,请执行该操作)来初始化另一个类
例如:
private async void b选择\u单击(对象发送方,事件参数e){
loadingSpiner.Visible=true;
btselect.Enabled=false;
int index=listProcess.SelectedIndex;
MainFormData数据=等待启动通知(索引);
Program.mainForm=新的mainForm(数据);
this.Hide();
Program.mainForm.Show();
}
专用异步任务startMainForm(int索引){
等待任务。运行(()=>{
MainFormData data=新的MainFormData();
初始化(运行进程[索引]);
返回数据;
});
}
类MainFormData
{
public MainFormData(){…}
//你们并没有说“runningProcess[index]”是什么,所以这里的占位符。。。
公共无效初始化(对象o){…}
}
差不多吧。当然,调整以适应你的需要
当然,另一个类必须只初始化非UI方面。即用户界面下的数据。由于创建UI对象通常并不耗时,因此我认为这在您的情况下是可行的。如果您觉得UI本身的初始化非常耗时,那么您应该寻求帮助,找出问题所在并解决问题。当然,这里没有一个好的MCVE,我也没有什么可以特别评论的。你不应该在uithread上打开任何ui。除了用来调用
应用程序的线程之外,你不能在任何线程上创建ui。运行——更常见的称为ui线程。我认为“默认形式”在Program.cs中指定运行应用程序时启动。在Program.cs中,您应该能够找到启动该表单的调用,该调用应该是阻塞的(因为此时我们是单线程的),然后添加代码以启动下一个表单?谢谢,我将MainForm构造函数中的所有逻辑(除了InitializeComponent())移到了返回“MainFormData”的任务中,所以我刚刚制作了一个新的主窗体(FormData),它工作得很好。再次感谢
this.Invoke(new MethodInvoker(delegate () { Program.mainForm.Show(); }));
private async void btnSelect_Click(object sender, EventArgs e) {
loadingSpiner.Visible = true;
btnSelect.Enabled = false;
int index = listProcess.SelectedIndex;
MainFormData data = await startMainForm(index);
Program.mainForm = new MainForm(data);
this.Hide();
Program.mainForm.Show();
}
private async Task<MainFormData> startMainForm(int index) {
await Task.Run(() => {
MainFormData data = new MainFormData();
data.Initialize(runningProcess[index]);
return data;
});
}
class MainFormData
{
public MainFormData() { ... }
// You don't say what "runningProcess[index]" is, so placeholder here...
public void Initialize(object o) { ... }
}