Как запустить новую форму в другом потоке в C #? - PullRequest
4 голосов
/ 14 августа 2010

Я просто пытаюсь запустить новый поток каждый раз, когда происходит нажатие кнопки, что должно создать новую форму.Я пробовал это в событии нажатия кнопки в 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();
}

Код в событии нажатия кнопки Subform выглядит следующим образом:

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 ]

13 голосов
/ 14 августа 2010

Вам не нужно запускать формы в отдельных потоках. Вы можете просто позвонить 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; };
}
3 голосов
/ 14 августа 2010

Хотя я не на 100% осведомлен обо всем, что говорит, что запуск полностью отдельных форм, выполнение полностью изолированных операций в их собственных потоках опасно в любом случае, выполнение всех операций пользовательского интерфейса в одном потоке обычно считается хорошей практикой.

Вы можете поддержать это, просто используя свой класс Subform, использующий BackgroundWorker.Когда форма отобразится, запустите BackgroundWorker, чтобы он обрабатывал все, что вам нужно.

Затем вы можете просто создать новые экземпляры вашей Subform в потоке 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);
}

Надеюсь, это поможет.

2 голосов
/ 10 июля 2017

Попробуй это. Он запускает новую форму в своем собственном потоке со своими собственными очередями сообщений, а что нет. Запустите этот код:

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

Используйте Thread.CurrentThread.GetHashCode() для проверки того, что он работает в другом потоке.

1 голос
/ 14 августа 2010

Возможно запускать разные формы в разных потоках.Я знаю о двух оговорках:

  1. Ни одна форма не может быть клиентом MDI другой.Попытка сделать форму клиентом MDI другого, когда формы имеют разные потоки, потерпит неудачу.
  2. Если объект будет отправлять события нескольким формам, и все формы используют один и тот же поток, можно синхронизировать события с основным потоком перед его поднятием.В противном случае событие должно вызываться асинхронно, и каждая форма должна выполнять собственный механизм синхронизации для входящих событий.

Очевидно, что желательно не блокировать поток пользовательского интерфейса какого-либо окна, но использование отдельных потоков для отдельных окон может быть хорошей альтернативой.

...