2

私は一般的にC#とGUI開発に不慣れです。これが古い質問である場合は、その情報源に私を誘導してください。この質問を削除します。

私の状況:つまり、1つの関数のコンソール出力をWindowsアプリケーションフォームのテキストボックスにリダイレクトするGUIを作成しています。コンソール出力には、デバイスのシリアル番号、現在のソフトウェアバージョンなどの情報がユーザーに表示されるだけです。

私の問題:このフォームはうまく機能しますが、ソフトウェアの更新プロセスに数分かかり、フォームが完了するまでフォームがフリーズします。今、私はバックグラウンドワーカーを実装することでこの問題が軽減されることを知っています。ただし、バックグラウンドワーカーを実装すると、次のエラーが発生します。

クロススレッド操作が無効です:コントロール'TextBox'は、それが作成されたスレッド以外のスレッドからアクセスされました。

私のコードの要約は次のとおりです。

public class Form1 : Form
{
    this.backgroundWorker1.DoWork += new
    System.ComponentModel.DoWorkEventHandler(this.backgroundWorker1_DoWork);

    private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
    {
         BackgroundWorker bw = sender as BackgroundWorker;     
         BigProcess(bw);
    }

    private void BigProcess(BackgroundWorker bw)
    {
        // lengthy operation that includes lots of
        Console.WriteLine("feedback stuff for the user");
    }

    private void button1_Click(object sender, EventArgs e)
    {
        this.backgroundWorker1.RunWorkerAsync();
    }
}

このプロジェクトには、コンソール出力のリダイレクトを処理TextBoxStreamWriterする派生クラスもあります。私はメソッドとメソッドをオーバーライドしてStringWriterいます。TextBoxStreamWriterWriteLineWrite

これが私がしていることの例です:

public override void WriteLine(string value)
{
      base.WriteLine(DateTime.Now.ToString(value));
      textBoxOutput.AppendText(value.ToString() + Environment.NewLine);
      writer.Write(value);
}

このメソッドが呼び出されると、InvalidOperationExceptionがスローされます。

どうすればこれをスレッドセーフにすることができますか?どんな助けでもいただければ幸いです。

4

3 に答える 3

1

テキストボックスの更新をUIスレッドに戻すだけです-例:

if (textBoxOutput.InvokeRequired)
{
  Invoke((MethodInvoker)(() => textBoxOutput.AppendText(value.ToString() + Environment.NewLine);
}
else
{
   textBoxOutput.AppendText(value.ToString() + Environment.NewLine)
}
于 2013-03-01T14:21:10.030 に答える
1

BackgroundWorkerイベントを公開します。RunWorkerCompletedこれは、長時間実行される操作の結果で UI を更新するために使用されます。そのイベントは UI スレッドで発生します。

そのため、UI スレッドに手動でマーシャリングするのではなく、そのイベントを処理するだけで済みます。

backgroundWorker1.RunWorkerCompleted += (s, args)=> 
    textBoxOutput.AppendText(args.Result.ToString() + Environment.NewLine);

次に、結果をDoWork印刷したいものに設定するだけです。

バックグラウンド処理全体で UI を更新する場合は、効果的に「進行状況の更新」があります。BGW には、バックグラウンド作業全体の進行状況に応じて UI を更新するためのサポートが組み込まれています。例については、BGW の MSDN ページを参照してください。

于 2013-03-01T15:05:24.670 に答える
0

これを試して:

public override void WriteLine(string value)
{
    if (InvokeRequired)
    {
        Invoke(() => WriteLine(value));
        return;
    }

    base.WriteLine(DateTime.Now.ToString(value));
    textBoxOutput.AppendText(value.ToString() + Environment.NewLine);
    writer.Write(value);
}

これは、フォームを所有しているスレッドとは異なるスレッドから WriteLine が呼び出されているかどうかを確認します。そうである場合は、フォームを所有するスレッドに、正しいスレッドでのみメソッドを再度呼び出すように要求します。

于 2013-03-01T14:21:10.527 に答える