我正在创建一个应用程序,它启动一个FormSelect(),要求用户在列表中选择一个项目,当用户按下"选择"按钮它将创建一个MainForm()的新实例,隐藏FormSelect并显示MainForm,但它不起作用,我在我做的所有测试中得到一个例外。
以下是一些代码:
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());
}
}
我的FormSelect上没什么特别的,所以这里是按钮点击它启动MainForm的地方:
private async void btnSelect_Click(object sender, EventArgs e) {
loadingSpiner.Visible = true;
btnSelect.Enabled = false;
int index = listProcess.SelectedIndex;
await startMainForm(index);
this.Hide();
Program.mainForm.Show();
}
private async Task startMainForm(int index) {
await Task.Run(() => {
Program.mainForm = new MainForm(runningProcess[index]);
});
}
正如您在上面所看到的,我使用任务来启动MainForm,因此它不会冻结我的UI和我的&#34;加载spiner&#34;
但是当它尝试使用.Show()时,我得到一个跨线程异常,所以我尝试使用以下方法调用该操作:
this.Invoke(new MethodInvoker(delegate () { Program.mainForm.Show(); }));
但是使用上面的方法我得到一个例外:
类型&#39; System.ComponentModel.Win32Exception&#39;的例外情况发生在System.Windows.Forms.dll中但未在用户代码中处理
其他信息:创建窗口句柄时出错。
如果我删除&#34;等待Task.Run()......&#34;在startMainForm方法中,一切正常,但它完全阻止了FormSelect UI。
我该如何避免这个问题?谢谢!
答案 0 :(得分:1)
你不能这样做。
如果没有可靠地再现问题的好Minimal, Complete, and Verifiable code example,就无法确定您的方案的最佳解决方案是什么。但是必须仅在UI线程中创建和使用UI对象。您无法在工作线程中创建MainForm
实例。
由于您的代码示例不完整,因此您不清楚为什么首先尝试使用MainForm
创建Task.Run()
实例。所有代码都是调用构造函数,构造函数不应该是耗时的操作。
如果你有一些耗时的初始化要执行,你应该从MainForm
类中抽象出来,把它放到一些其他类中,一旦它被完全初始化就可以传递给MainForm
。然后你可以用例如初始化那个其他类调用Task.Run()
(但仍然不在构造函数中......创建对象,然后如果需要异步调用初始化它的方法,那么就这样做。)
E.g:
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) { ... }
}
这样的事情。当然,调整以满足您的需求。
当然,其他类必须只初始化非UI方面。即您的UI底层数据。由于创建UI对象通常不费时,我认为在您的情况下这是可行的。如果你认为这是UI本身的初始化是耗时的,那么你应该寻求帮助来弄清楚是什么情况并解决这个问题。当然,在这里没有一个好的MCVE,我没有什么可以就此特别评论。