C# 从另一个线程调用 form.show()

Posted

技术标签:

【中文标题】C# 从另一个线程调用 form.show()【英文标题】:C# calling form.show() from another thread 【发布时间】:2012-08-13 07:01:24 【问题描述】:

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

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

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

【问题讨论】:

"form will not show at real." - 我不知道那是什么意思。您是在问如何显示一个同时不阻塞的“模态”对话框? 我想出示表格。我不知道怎么做。我的意思是上面的代码将显示表单,但会显示一段时间,因为线程将退出并带有它的表单。如果我显示模态对话框,线程将停止并显示表单。但是它下面的代码将在关闭对话框后完成,这就是我不想要的。 【参考方案1】:

尝试使用调用调用:

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 对象,它们也可以工作。

【讨论】:

这对我不起作用。 “在创建窗口句柄之前,不能在控件上调用 Invoke 或 BeginInvoke。” 嗯 - 好吧,让我们稍微编辑一下。我也把你的问题改写了一点,我希望它仍然很清楚。 使用 lambdas 代替委托。 嗨,你能解释一下你在上面的代码中做了什么吗?我有类似的问题,我想在不中断 form1 执行的情况下显示与 form1 不同的表单,比如 Form2。您的解决方案是否也在做同样的事情?【参考方案2】:

您应该在拨打form.Show() 之后拨打Application.Run()。例如:

public void showForm() 

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

至于背后的原因,this msdn post 可能会有所帮助。

【讨论】:

这将在另一个线程中启动一个新的消息循环 - 当主线程上已经有一个正在运行的消息循环时启动一个新的消息循环可能是过度的......【参考方案3】:

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

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();

【讨论】:

好主意 (ReportPre)Application.OpenForms["ReportPre"] thx u【参考方案4】:

如果您的用例是在主 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 是一个简单的表单,带有一个公共标签和一个样式设置为 Marquee 的 ProgressBar

【讨论】:

以上是关于C# 从另一个线程调用 form.show()的主要内容,如果未能解决你的问题,请参考以下文章

信号没有从另一个线程调用槽

从另一个线程调用 Boost 线程 Sleep_For()

从另一个 C# 应用程序调用 C# 应用程序中的方法 [重复]

c#如何调用MidMid()

从另一个 C# DotNet DLL 动态加载和调用 C# DotNet DLL

使用线程从另一个成员函数调用一个成员函数