表单显示不使用线程

时间:2016-09-21 23:27:11

标签: c# .net winforms

我正在创建一个应用程序,它启动一个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。

我该如何避免这个问题?谢谢!

1 个答案:

答案 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,我没有什么可以就此特别评论。