26

如果我form.show()从另一个线程调用 WinForms 对象,表单将引发异常。我可以在哪里向主应用程序线程添加一个新的可见表单?否则,如何在不停止当前正在执行的线程的情况下打开表单?

这是我的示例代码。我正在尝试启动一个线程,然后在该线程中执行一些工作。随着工作的进展,我将展示表格。

public void Main()
{
    new Thread(new ThreadStart(showForm)).Start();
    // Rest of main thread goes here...
}

public void showForm() 
{
    // Do some work here.
    myForm form = new myForm();
    form.Text = "my text";
    form.Show();
    // Do some more work here
}
4

4 回答 4

36

尝试使用调用调用:

public static Form globalForm;

void Main()
{
    globalForm = new Form();
    globalForm.Show();
    globalForm.Hide();
    // Spawn threads here
}

void ThreadProc()
{
    myForm form = new myForm();
    globalForm.Invoke((MethodInvoker)delegate() {
        form.Text = "my text";
        form.Show();
    });
}

“invoke”调用告诉表单“请在你的线程而不是我的线程中执行此代码”。然后,您可以从委托中更改 WinForms UI。

有关 Invoke 的更多文档在这里:http: //msdn.microsoft.com/en-us/library/zyzhdc6b.aspx

编辑:您需要使用已经存在的 WinForms 对象才能调用调用。我在这里展示了如何创建一个全局对象;否则,如果您有任何其他 windows 对象,它们也将起作用。

于 2012-08-16T21:16:55.213 回答
13

你应该打电话Application.Run()后打电话form.Show()。例如:

public void showForm() 
{
    // Do some work here.
    myForm form = new myForm();
    form.Text = "my text";
    form.Show();
    Application.Run();
    // Do some more work here
}

至于背后的细节,这个 msdn 帖子可能会有所帮助。

于 2013-04-12T00:29:40.203 回答
1

根据我的经验,最好的方法:

var ac = (ReportPre)Application.OpenForms["ReportPre"];
Thread shower = new Thread(new ThreadStart(() =>
    {
        if (ac == null)
        {                
            this.Invoke((MethodInvoker)delegate () {
                ac = new ReportPre();
                ac.Show();
            });       
        }
        else
        {
            this.Invoke((MethodInvoker)delegate
            {
                pictureBox1.Visible = true;
            });
            if (ac.InvokeRequired)
            {
                ac.Invoke(new MethodInvoker(delegate {
                    ac.Hide();
                    ac.Show();
                }));                          
            }
        }
    }));
shower.Start();
于 2018-07-30T19:19:57.957 回答
-1

如果您的用例是在主 GUI 线程忙(如加载栏)时显示 GUI,您可以执行以下操作:

private void MethodWithLoadingBar()
{
    Thread t1 = new Thread(ShowLoading);
    t1.Start();
    // Do the Main GUI Work Here
    t1.Abort();
}

private void ShowLoading()
{
    Thread.Sleep(1000); //Uncomment this if you want to delay the display 
                        //(So Loading Bar only shows if the Method takes longer than 1 Second)
    loadingGUI = new LoadingGUI();
    loadingGUI.label1.Text = "Try to Connect...";
    loadingGUI.ShowDialog();
}

我的 LoadingGUI 是一个简单的表单,带有一个公共标签和一个带有样式设置为选取框的 ProgressBar

于 2020-07-14T10:11:29.340 回答