4

我只是在每次单击按钮时都尝试运行一个新线程,这应该创建一个新表单。我在 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();
}

子窗体按钮单击事件中的代码如下所示:

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

这是正确的方法吗?因为我试图打开两个独立的表单,一个线程中的操作不应该影响另一个线程。

或者 BackGroundworker 是实现这一点的解决方案吗?如果是的话,有人可以帮我吗?

4

4 回答 4

13

您不需要在单独的线程中运行表单。您可以s.Show()正常调用多个表单。他们不会互相阻挡。

当然,如果您正在做其他事情,例如某种计算或其他需要很长时间的任务,那么您应该在单独的线程中运行它,而不是在表单中运行。

这里有一些代码可以让你创建一个进度条来显示一个长过程的进度。请注意,每次从线程内部访问表单时,您都必须使用.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; };
}
于 2010-08-14T10:38:23.810 回答
3

尽管我不是 100% 意识到运行完全独立的表单在自己的线程中执行完全隔离的操作在任何方面都是危险的,但在单个线程上运行所有 UI 操作通常被认为是一种好的做法。

您可以通过让您的 Subform 类使用 BackgroundWorker 来支持这一点。显示表单后,启动 BackgroundWorker 以便它处理您需要的任何内容。

然后您可以简单地在您的 GUI 线程上创建您的 Subform 的新实例并显示它们。该表单将显示并在另一个线程上开始其操作。

这样,UI 将在 GUI 线程上运行,但表单正在运行的操作将在 ThreadPool 线程上运行。

更新

这是您的后台工作处理程序可能看起来的示例 - 请注意(像往常一样)这只是我的想法,但我认为您可以了解基本原则。

将 BackgroundWorker 添加到名为 worker 的表单中。将其连接到以下事件处理程序:

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

您的点击处理程序看起来像:

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

我希望这会有所帮助。

于 2010-08-14T10:42:11.873 回答
2

尝试这个。它使用自己的消息队列在自己的线程上运行新表单,等等。运行此代码:

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

用于Thread.CurrentThread.GetHashCode()测试在不同线程上运行。

于 2017-07-10T12:42:26.263 回答
0

可以在不同的线程上运行不同的表单。我知道有两个警告:

  1. 任何一种形式都不能是另一方的 MDI 客户端。当表单具有不同的线程时,试图使一个表单成为另一个表单的 MDI 客户端将会失败。
  2. 如果一个对象将向多个表单发送事件并且所有表单都使用同一个线程,则可以在引发事件之前将事件同步到主线程。否则,必须异步引发事件,并且每个表单必须为传入事件执行自己的同步机制。

显然,最好不要让任何窗口的 UI 线程被阻塞,但是为单独的窗口使用单独的线程可能是一个不错的选择。

于 2010-08-14T14:50:49.057 回答