16

私はそれが機能するクラスにバックグラウンドワーカーを作成しましたが、呼び出して最後の実行まで待つと、2回目に呼び出すと同じプロセスが2回実行されます

bw.DoWorkに何か問題があると思います+=

private void button1_Click(object sender, EventArgs e)
{
    nptest.test.start("null", "null");    
}


namespace nptest
{
    class test
    {
        public static void start(string str, string strb)
        {
            if (bw.IsBusy != true)
            {
                bw.WorkerSupportsCancellation = true;
                bw.DoWork += (obj, e) => bw_DoWork(str, strb);
                bw.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bw_RunWorkerCompleted);
                bw.RunWorkerAsync();
            }
        }
        private static BackgroundWorker bw = new BackgroundWorker();
        private static void bw_DoWork(string str, string strb)
        {
            System.Windows.Forms.MessageBox.Show("initializing BackgroundWorker");
        }
        private static void bw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            if ((e.Cancelled == true))
            {
                Console.WriteLine("Canceled");
            }
            else if (!(e.Error == null))
            {
                Console.WriteLine("Error: " + e.Error.Message);
            }
            bw.Dispose();

        }
    }
}

問題が解決しました

  class test
    {
        private static List<object> arguments = new List<object>();

        // initializing with program startup
        public static void bwinitializing()
        {
            bw.WorkerSupportsCancellation = true;
            bw.DoWork += new DoWorkEventHandler(bw_DoWork);
            bw.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bw_RunWorkerCompleted);
        }

        public static void start(string str, string strb)
        {
            if (bw.IsBusy != true)
            {
                arguments.Clear();
                arguments.Add(str);
                arguments.Add(strb);
                bw.RunWorkerAsync(arguments);
            }
        }
        private static BackgroundWorker bw = new BackgroundWorker();
        private static void bw_DoWork(object sender, DoWorkEventArgs e)
        {
            List<object> genericlist = e.Argument as List<object>;
            System.Windows.Forms.MessageBox.Show("BackgroundWorker " + genericlist[0]);

        }
4

7 に答える 7

16

複数の DoWorkイベントが誤って追加されているのではないかと思います。

つまり、メソッドが呼び出されるたびに、新しいイベントハンドラーが登録されます。これにより、既存のハンドラーハンドラーが追加され、置き換えられません。したがって、後続の時間.. 1、2、3などと呼ばれる複数のハンドラーがあります。start DoWorkDoWorkDoWork

// creates a NEW delegate and adds a NEW handler
bw.DoWork += (obj, e) => bw_DoWork(str, strb);

ここではクロージャを使用せ、メソッドグループ(デリゲートへの暗黙の変換を含む)を使用してから、データを呼び出しに渡すことをお勧めしRunWorkerAsyncます(データの引数を取るフォームがあります)。

この行には、メソッドグループからデリゲートが渡されるため(常に同じデリゲートオブジェクト1RunWorkerCompleted +=に評価されることが保証されているため)、この問題は発生しません。したがって、その行を繰り返し呼び出すと、ハンドラーが置き換えられます。+=


例:

class MyData {
   public string StrA { get; set; }
}

// These only need to be setup once (and should be for clarity).
// However it will be "ok" now if they are called multiple times
// as, since the delegates are the same, the += will
// act as a replacement (as it replaces the previous delegate with itself).
bw.WorkerSupportsCancellation = true;
bw.DoWork += bw_DoWork;
bw.RunWorkerCompleted += bw_RunWorkerCompleted;

// Pass data via argument
bw.RunWorkerAsync(new MyData {
    StrA = str,
});

void bw_DoWork (object sender, DoWorkEventArgs e) {
    var data = (MyData)e.Argument;
    var str = data.StrA;
    // stuff
}

1参照が等しいことが保証されているかどうかはわかりませんが、このアプローチを使用すると、によって取得された場合でも、メソッドグループからのデリゲートの安定した呼び出しが可能に+=なり-=ますnew DelegateType(MethodGroup)

に関して。メインの投稿での私のコメント:UI要素が作成されていないスレッドからアクセスされる場合、楽しい「クロススレッド操作の例外」があります。このメッセージボックスの使用法は「大丈夫」(別のスレッドの所有者で作成されていない場合)だと思いますが、BackgroundWorkerのDoWorkでUIにアクセスする方法は一般的に疑わしいものです。


また、ここに電話しないbw.Dispose()でください。所有するコンテナまたはコンテキストで破棄します。この場合は良性で良性のように見えますが、そのBGWインスタンスが二度と使用されない場合にのみ実行してください。BGWはまだ「アクティブ」であるため、イベントハンドラーから呼び出すことも疑わしいです。

于 2012-09-01T21:09:16.260 に答える
15

上記のコメンテーター「パワーMOSFET」と同じ問題が発生しました

new BackgroundWorker()そして最後に、グローバルbw値にthenを追加すると、問題が解決します。

コードは、次の場所から変更します。

private BackgroundWorker gBgwDownload;

private void yourFunction_bw(xxx)
{
    // Create a background thread
    gBgwDownload.DoWork += bgwDownload_DoWork;
    gBgwDownload.RunWorkerCompleted += bgwDownload_RunWorkerCompleted;
    //omited some code
    gBgwDownload.RunWorkerAsync(paraObj);
}

に:

private BackgroundWorker gBgwDownload;

private void yourFunction_bw(xxx)
{
    // Create a background thread
    gBgwDownload = new BackgroundWorker(); /* added this line will fix problem */
    gBgwDownload.DoWork += bgwDownload_DoWork;
    gBgwDownload.RunWorkerCompleted += bgwDownload_RunWorkerCompleted;
    //omited some code
    gBgwDownload.RunWorkerAsync(paraObj);

}
于 2013-03-22T08:15:19.713 に答える
5

別の理由もあります。DoWorkEventHandler生成されたコードを探しInitializeComponent()ます。コンポーネントのUIプロパティを使用して生成し、自分で登録した場合。

再度登録すると、前のイベントは上書きされませんが、別のイベントが追加され、2回呼び出されるためです。

于 2014-01-10T03:11:37.827 に答える
3

私の場合、フォームのコンストラクタークラスでDoWork、ProgressChanged、およびRunWorkerCompletedイベントハンドラーを宣言したため、BackgroundWorkerは2回実行されていましたが、このフォームクラスのDesigner部分でVisualStudio2013によって既に宣言されています。

だから、私は自分の宣言を削除しただけで、うまくいきました。

于 2015-05-27T15:15:22.913 に答える
0

ありがとう....このコードは正常に機能しています...backroundworkerの新しいインスタンスを作成することをお勧めします....これで、この関数をfor / whileループで呼び出して、複数のbackgroundworkerプロセスを実行できます。

ボタンのクリックが完了したときにこのようにコーディングしました..メインスレッドフローを混乱させることなく...複数のプロセスが裏側で実行されます....メッセージボックスを使用してポップアップしました..しかし、「で実行するために時間のかかるプロセスを実行できますbgwDownload_DoWork"関数...そして複数のプロセスが作成されます...そして彼女はBackgroundWorkerがビジーかどうかをチェックする必要はありません...

private void button1_Click(object sender, EventArgs e)
{
   for (int i = 0; i < 3; i++)
     yourFunction_bw(i);

 }
private BackgroundWorker gBgwDownload;

private void yourFunction_bw(int i)
{
    // Create a background thread
    gBgwDownload = new BackgroundWorker(); // added this line will fix problem 
    gBgwDownload.DoWork += bgwDownload_DoWork;
    gBgwDownload.RunWorkerAsync(i);

}

private void bgwDownload_DoWork(object sender, DoWorkEventArgs e)
{
  int stre = (int)e.Argument;
  MessageBox.Show(stre.ToString ()); // time taken process can be added here
}
于 2013-04-18T06:43:07.473 に答える
0

今日この問題に遭遇しました。フォームを表示するたびにバックグラウンドワーカーのRunWorkerCompletedイベントが複数回呼び出されていることに気付いたときに、長時間実行タスクを実行しているポップアップフォームにバックグラウンドワーカーを配置しました。

私の問題は、フォームを閉じた後にフォームを破棄していなかったことです。つまり、フォームを表示するたびに、毎回別のハンドラーが追加されていました。

終了時にフォームを破棄すると、問題が解決しました。私が自分の状況の解決策を探しに行ったときにこのページに出くわしたので、ここでそれについて言及したかっただけです。

于 2013-06-22T15:44:41.253 に答える
0

デザイナからコントロールを削除し、コードで新しいWorkerProcessをインスタンス化しました。

例:var bwProcess = new BackgroundWorker();

bwProcess.DoWork + = new DoWorkEventHandler(bwProcess_DoWork);

bwProcess.RunWorkerCompleted + = bwProcess_RunWorkerCompleted;

于 2018-10-31T08:48:58.247 に答える