简体   繁体   English

如何在C#中的不同线程上运行新表单?

[英]How can a new Form be run on a different thread in C#?

I'm just trying to run a new thread each time a button click even occurs which should create a new form. 我只是尝试在每次按钮点击时都运行一个新线程,这应该创建一个新表单。 I tried this in the button click event in the MainForm: 我在MainForm中的按钮单击事件中尝试了这个:

private void button1_Click(object sender, EventArgs e)
{
    worker1 = new Thread(new ThreadStart(thread1));
    worker2 = new Thread(new ThreadStart(thread2));

    worker1.Start();
    worker2.Start();
}

private void thread1()
{
    SubForm s = new SubForm();
    s.Show();
}

private void thread2()
{
    SubForm s = new SubForm();
    s.Show();
}

The code in the Subform button click event goes like this: 子窗体按钮单击事件中的代码如下所示:

private void button1_Click(object sender, EventArgs e)
{
    int max;
    try
    {
        max = Convert.ToInt32(textBox1.Text);
    }
    catch
    {
        MessageBox.Show("Enter numbers", "ERROR");
        return;
    }

    progressBar1.Maximum = max;

    for ( long i = 0; i < max; i++)
    {
        progressBar1.Value = Convert.ToInt32(i);
    }          
}

Is this the right way? 这是正确的方法吗? Because I'm trying to open two independent forms, operations in one thread should not affect the other thread. 因为我试图打开两个独立的表单,一个线程中的操作不应该影响另一个线程。

Or is BackGroundworker the solution to implement this? 或者BackGroundworker是实现这个的解决方案吗? If yes, can anyone please help me with that? 如果是的话,有人可以帮助我吗?

You do not need to run forms in separate threads. 您不需要在单独的线程中运行表单。 You can just call s.Show() on multiple forms normally. 你可以通常在多个表单上调用s.Show() They will not block each other. 他们不会互相阻挠。

Of course, if you're doing something else , like some sort of calculation or other task that takes a long while, then you should run that in a separate thread, but not the form. 当然,如果你正在做其他事情 ,比如某种计算或需要很长时间的其他任务,那么你应该在一个单独的线程中运行 ,而不是表单。

Here is a bit of code that will let you create a progress bar that shows progress for a long process. 这里有一些代码可以让您创建一个显示长进程进度的进度条。 Notice that every time to access the form from inside the thread, you have to use .Invoke() , which actually schedules that invocation to run on the GUI thread when it's ready. 请注意,每次从线程内部访问表单时,都必须使用.Invoke() ,它实际上会调度该调用在GUI线程准备就绪时运行。

public void StartLongProcess()
{
    // Create and show the form with the progress bar
    var progressForm = new Subform();
    progressForm.Show();
    bool interrupt = false;

    // Run the calculation in a separate thread
    var thread = new Thread(() =>
    {
        // Do some calculation, presumably in some sort of loop...
        while ( ... )
        {
            // Every time you want to update the progress bar:
            progressForm.Invoke(new Action(
                () => { progressForm.ProgressBar.Value = ...; }));

            // If you’re ready to cancel the calculation:
            if (interrupt)
                break;
        }

        // The calculation is finished — close the progress form
        progressForm.Invoke(new Action(() => { progressForm.Close(); }));
    });
    thread.Start();

    // Allow the user to cancel the calculation with a Cancel button
    progressForm.CancelButton.Click += (s, e) => { interrupt = true; };
}

Although I'm not 100% aware of anything that says running completely seperate forms doing completely isolated operations in their own threads is dangerous in any way, running all UI operations on a single thread is generally regarded as good practice. 虽然我不是100%意识到任何说完全分离的表单在自己的线程中完全独立的操作是危险的,但在单个线程上运行所有UI操作通常被认为是一种好的做法。

You can support this simply by having your Subform class use BackgroundWorker. 只需让Subform类使用BackgroundWorker即可支持此功能。 When the form is shown, kick off the BackgroundWorker so that it processes whatever you need it to. 显示表单后,启动BackgroundWorker,以便它处理您需要的任何内容。

Then you can simply create new instances of your Subform on your GUI thread and show them. 然后,您只需在GUI线程上创建Subform的新实例并显示它们。 The form will show and start its operation on another thread. 表单将显示并在另一个线程上启动其操作。

This way the UI will be running on the GUI thread, but the operations the forms are running will be running on ThreadPool threads. 这样UI将在GUI线程上运行,但表单运行的操作将在ThreadPool线程上运行。

Update 更新

Here's an example of what your background worker handlers might look like - note that (as usual) this is just off the top of my head, but I think you can get your head around the basic principles. 以下是您的后台工作人员可能看起来的样子 - 注意(像往常一样)这只是我的头脑,但我认为您可以了解基本原则。

Add a BackgroundWorker to your form named worker. 将BackgroundWorker添加到名为worker的表单中。 Hook it up to the following event handlers: 将其连接到以下事件处理程序:

void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
    // Executed on GUI thread.
    if (e.Error != null)
    {
        // Background thread errored - report it in a messagebox.
        MessageBox.Show(e.Error.ToString());
        return;
    }

    // Worker succeeded.
}

void worker_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
    // Executed on GUI thread.
    progressBar1.Value = e.ProgressPercentage;
}

void worker_DoWork(object sender, DoWorkEventArgs e)
{
    // Executed on ThreadPool thread.
    int max = (int)e.Argument;

    for (long i = 0; i < max; i++)
    {
        worker.ReportProgress(Convert.ToInt32(i));
    }
}

Your click handler would look something like: 您的点击处理程序看起来像:

void button1_Click(object sender, EventArgs e)
{
    int max;

    try
    {
        // This is what you have in your click handler,
        // Int32.TryParse is a much better alternative.
        max = Convert.ToInt32(textBox1.Text);
    }
    catch
    {
        MessageBox.Show("Enter numbers", "ERROR");
        return;
    }

    progressBar1.Maximum = max;

    worker.RunWorkerAsync(max);
}

I hope that helps. 我希望有所帮助。

Try this. 尝试这个。 It runs the new Form on its own thread with its own message queues and what not. 它在自己的线程上运行新的Form,它有自己的消息队列,什么不是。 Run this code: 运行此代码:

new Thread(new ThreadStart(delegate
{
   Application.Run(new Form());
})).Start();

Use Thread.CurrentThread.GetHashCode() to test that is runs on different thread. 使用Thread.CurrentThread.GetHashCode()来测试它是否在不同的线程上运行。

It's possible to run different forms on different threads. 可以在不同的线程上运行不同的表单。 There are two caveats I'm aware of: 我知道有两个警告:

  1. Neither form may be an MDI client of the other. 这两种形式都不是另一种形式的MDI客户端。 Attempting to make a form an MDI client of another when the forms have different threads will fail. 当表单具有不同的线程时,尝试使表单成为另一个的MDI客户端将失败。
  2. If an object will be sending events to multiple forms and all forms use the same thread, it's possible to synchronize the events to the main thread before raising it. 如果一个对象将事件发送到多个表单并且所有表单都使用相同的线程,则可以在提升之前将事件同步到主线程。 Otherwise, the event must be raised asynchronously and each form must perform its own synchronization mechanism for incoming events. 否则,必须异步引发事件,并且每个表单必须为传入事件执行自己的同步机制。

Obviously it's desirable not to have any window's UI thread get blocked, but using separate threads for separate windows may be a nice alternative. 显然,不希望任何窗口的UI线程被阻止,但是为单独的窗口使用单独的线程可能是一个不错的选择。

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

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