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

これは正しい方法ですか?2つの独立したフォームを開こうとしているので、一方のスレッドでの操作がもう一方のスレッドに影響を与えることはありません。

それとも、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操作を単一のスレッドで実行することは一般的に良い習慣と見なされます。

サブフォームクラスにBackgroundWorkerを使用させるだけで、これをサポートできます。フォームが表示されたら、BackgroundWorkerを起動して、必要なものをすべて処理します。

次に、GUIスレッドでサブフォームの新しいインスタンスを作成して表示するだけです。フォームが表示され、別のスレッドで操作が開始されます。

このように、UIはGUIスレッドで実行されますが、フォームが実行している操作はThreadPoolスレッドで実行されます。

アップデート

これは、バックグラウンドワーカーハンドラーがどのように見えるかの例です-(いつものように)これは私の頭のすぐ上にあることに注意してください、しかし私はあなたが基本的な原則に頭を悩ませることができると思います。

ワーカーという名前のフォームにBackgroundWorkerを追加します。次のイベントハンドラーに接続します。

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

さまざまなスレッドでさまざまなフォームを実行することが可能です。私が知っている2つの警告があります:

  1. どちらのフォームも、もう一方のMDIクライアントにはなりません。フォームのスレッドが異なるときにフォームを別のMDIクライアントにしようとすると、失敗します。
  2. オブジェクトが複数のフォームにイベントを送信し、すべてのフォームが同じスレッドを使用する場合、イベントを発生させる前にイベントをメインスレッドに同期させることができます。それ以外の場合、イベントは非同期で発生する必要があり、各フォームは着信イベントに対して独自の同期メカニズムを実行する必要があります。

明らかに、ウィンドウのUIスレッドがブロックされないことが望ましいですが、別々のウィンドウに別々のスレッドを使用することは良い代替手段かもしれません。

于 2010-08-14T14:50:49.057 に答える