DoWork of BackgroundWorker вызывается дважды, когда RunWorkerAsync вызывается один раз?

Я создал фонового рабочего в классе, который он работает, но если я вызову и дождитесь окончания, вызовите его во второй раз, он будет выполнять тот же процесс дважды

Я думаю, что что-то не так с 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]);

        }

Ответ 1

Я бы заподозрил, что несколько событий DoWork непреднамеренно добавлены.

То есть, каждый раз, когда вызывается метод start, он регистрирует новый обработчик события DoWork. Это добавляет и не заменяет обработчик обработчика DoWork. Итак, тогда будет несколько обработчиков DoWork, называемых последующими временами. 1, 2, 3 и т.д.

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

Я бы рекомендовал не использовать здесь закрытие, а просто использовать группу методов (с неявным преобразованием в делегат), а затем передать данные в вызов RunWorkerAsync (есть форма, которая принимает аргумент для данных).

В строке RunWorkerCompleted += эта проблема отсутствует, поскольку она передается делегатом из группы методов (которая всегда будет оценивать один и тот же объект-делегат 1). Таким образом, повторяющийся += вызывает эту строку, заменит обработчик.


Пример:

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 Я не уверен, что гарантированно равенство равенства ссылок, но использование этого подхода позволяет стабильно вызывать += и -= из делегата из группы Method even если получена new DelegateType(MethodGroup).

Wrt. мой комментарий в главном сообщении: если элементы пользовательского интерфейса доступны из потока, на котором они не были созданы, тогда будет весело "Перекрестные операции". Я считаю, что использование Message Box - это "нормально" (если оно не создано с помощью владельца из другого потока), но практика доступа к пользовательскому интерфейсу в BackgroundWorker DoWork обычно сомнительна.


Кроме того, не вызывайте bw.Dispose() здесь; распоряжаться им контейнером или контекстом. В этом случае он выглядит приятным и доброкачественным, но это делается только тогда, когда этот экземпляр BGW больше никогда не будет использоваться. Вызов его из обработчика событий также сомнительный, поскольку BGW по-прежнему "активен".

Ответ 2

Я столкнулся с той же проблемой, что и выше комментатор "Power-Mosfet"

и, в конце концов, добавленный new BackgroundWorker(), затем назначенный глобальному значению bw, исправит мою проблему.

code is, change from:

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

}

Ответ 3

Есть и еще одна причина. ищите DoWorkEventHandler в сгенерированном коде InitializeComponent() Если вы сгенерировали его через свойства compnent UI, а также сами зарегистрировали его.

Потому что, если вы зарегистрируете его снова, он не переопределит предыдущий, а добавит другое событие и вызовет дважды.

Ответ 4

В моем случае BackgroundWorker выполнялся дважды, потому что в классе конструктора моей формы я объявлял обработчики событий DoWork, ProgressChanged и RunWorkerCompleted, но уже был объявлен Visual Studio 2013 в конструкторской части этого класса формы.

Итак, я просто удалил свои объявления и работал нормально.

Ответ 5

спасибо.... этот код работает отлично... создание нового заработка для backroundworker - хорошая идея.... Теперь мы можем вызвать эту функцию для цикла /while и запустить несколько процессов backgroundworker.

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

Ответ 6

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

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

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