简体   繁体   English

如何从非gui线程C#中创建表单

[英]How to Create Form from within non gui thread C#

I have my main GUI from where I start a long running method in a separate thread. 我有一个主GUI,我从一个单独的线程中开始一个长时间运行的方法。 Now from within this separate thread I need to create and show a new form. 现在,在这个单独的线程中,我需要创建并显示一个新表单。 But when I show this new form all the controls are stuck an the window says "not responding". 但是,当我显示这个新表单时,所有控件都被卡住,窗口显示“没有响应”。

Which is the best way of solving this ?? 哪个是解决这个问题的最佳方法?

regards 问候

Thomas 托马斯

Put the code that creates the new GUI into the main GUI class and then call the main GUI's Invoke method, or raise an event that the main GUI can subscribe to to know when to trigger the new GUI. 将创建新GUI的代码放入主GUI类,然后调用主GUI的Invoke方法,或者引发主GUI可以订阅的事件,以了解何时触发新GUI。 If you choose the latter, be sure to use InvokeRequired to determine if you can call the method that creates the new GUI directly or if you need to use an Invoke to get back onto the GUI thread to create the new GUI. 如果选择后者,请确保使用InvokeRequired确定是否可以直接调用创建新GUI的方法,或者是否需要使用Invoke返回GUI线程来创建新GUI。

You need to learn about Control.BeginInvoke/Invoke and all that means. 您需要了解Control.BeginInvoke / Invoke以及所有这些。 Just remember that all UI operations need to occur on the main thread (UI thread) because that is the thread that owns the message pump. 请记住,所有UI操作都需要在主线程(UI线程)上进行,因为这是拥有消息泵的线程。 You need to call back into that thread in order to have UI actions happen. 您需要回调该线程才能执行UI操作。

Here's an intro to the BeginInvoke/Invoke stuff: http://weblogs.asp.net/justin_rogers/pages/126345.aspx 这是BeginInvoke / Invoke的介绍: http//weblogs.asp.net/justin_rogers/pages/126345.aspx

In order to help further here's a complete working code example that should highlight the basics. 为了进一步提供帮助,这里有一个完整的工作代码示例,应该突出基础知识。

public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();
    }

    private void button1_Click(object sender, EventArgs e)
    {
        var worker = new Worker(this);
        worker.Start();
    }

    public void updateLabel(int value)
    {
        if(label1.InvokeRequired) { // check if on UI thread
            //If true use begin invoke to call update on UI thread
            //this calls the anonymous delegate in the UI thread
            //that then calls the updateLabel function again to set the label's text
            label1.BeginInvoke(new MethodInvoker(() => this.updateLabel(value)));
            return;
        }

        label1.Text = value.ToString();
    }

    public void showNewForm()
    {
        if(this.InvokeRequired) { // check if on UI thread
            this.BeginInvoke(new MethodInvoker(this.showNewForm)); // we need to create the new form on the UI thread
            return;
        }

        var anotherForm = new Form1();
        anotherForm.Show();
    }
}

class Worker
{
    private volatile bool stop = false;
    private Form1 form;

    public Worker(Form1 form)
    {
        this.form = form;
    }

    public bool Stop
    {
        get
        {
            return stop;
        }
        set
        {
            stop = value;
        }
    }

    public void Start()
    {
        var thread = new Thread(this.work);
        thread.IsBackground = true;
        thread.Start();
    }

    private void work()
    {
        int i = 0;
        while(!stop) {
            i++;
            Thread.Sleep(100);

            form.updateLabel(i);
            if(i == 50) {
                form.showNewForm(); // call into form
                // can also do the invokerequired check here and create new form w/ anonymous functions
                // however, I'd recommend keeping all the UI code in the same place.
            }
        }
    }
}

Use Form.Show instead of Form.ShowDialog. 使用Form.Show而不是Form.ShowDialog。 You can also use a BackgroundWorker to do concurrent tasks. 您还可以使用BackgroundWorker执行并发任务。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM