Отправка аргументов фоновому работнику?

147

Допустим, я хочу отправить параметр int фоновому работнику, как это можно сделать?

private void worker_DoWork(object sender, DoWorkEventArgs e) {

}

Я знаю, когда это - worker.RunWorkerAsync (); я не понимаю, как определить в worker_DoWork, что он должен принимать параметр int.

sooprise
источник

Ответы:

235

Вы начинаете это так:

int value = 123;
bgw1.RunWorkerAsync(argument: value);  // the int will be boxed

а потом

private void worker_DoWork(object sender, DoWorkEventArgs e) 
{
   int value = (int) e.Argument;   // the 'argument' parameter resurfaces here

   ...

   // and to transport a result back to the main thread
   double result = 0.1 * value;
   e.Result = result;
}


// the Completed handler should follow this pattern 
// for Error and (optionally) Cancellation handling
private void worker_Completed(object sender, RunWorkerCompletedEventArgs e) 
{
  // check error, check cancel, then use result
  if (e.Error != null)
  {
     // handle the error
  }
  else if (e.Cancelled)
  {
     // handle cancellation
  }
  else
  {          
      double result = (double) e.Result;
      // use it on the UI thread
  }
  // general cleanup code, runs when there was an error or not.
}
Хенк Холтерман
источник
38
Как я могу сделать два аргумента?
сюрприз
3
Или я отправляю объект, полный более чем одного аргумента?
sooprise
23
@soo: Используйте вспомогательный класс или Tuple<A,B>(C # 4 +) (Правка: Да, используйте объект, чтобы упаковать все это. Смотрите, например, DoWorkEventArgs self).
Хенк Холтерман
Но как вы уведомите пользовательский интерфейс о результате?
Rayray
1
@rayray: label1.Text = e.Result.ToString();везде я отмечал это как безопасный.
Хенк
102

Несмотря на то, что это уже отвеченный вопрос, я бы оставил еще один вариант, который намного проще читать по ИМО:

BackgroundWorker worker = new BackgroundWorker();
worker.DoWork += (obj, e) => WorkerDoWork(value, text);
worker.RunWorkerAsync();

И по методу обработчика:

private void WorkerDoWork(int value, string text) {
    ...
}
dcarneiro
источник
12
Я не знал, что означает IMO, я думал, что это C # вещь. Я погуглил "C # IMO" и приземлился здесь, и получил ответ ... lol quantnet.com/threads/cc-vba-or-java.11433
electricbah
Как насчет 3 параметров?
Юки Сакура
Я не играю с .NET с 2012 года, но если я не ошибаюсь, вы можете добавить ... => WorkerDoWork(a, b, c);... WorkerDoWork(int a, string b, string c) {...
нужные
1
Имейте в виду, что если вы использовали это (как я пытался сделать), вы должны каждый раз создавать нового фонового работника (в вашем примере вы это сделали). Иначе у вас будет проблема, как у меня. Мой фоновый работник будет повторять предыдущие прогоны. Если запустить один раз, все было в порядке. 2 раза повторяется последний запуск и текущий запуск. 3-й пробег будет повторять последние два и текущий. и т. д.
bshea
Но как значение передается в RunWorkerAsync?
CodyBugstein
47

Вы можете передать несколько аргументов, как это.

List<object> arguments = new List<object>();
                    arguments.Add(argument 1);
                    arguments.Add(argument 1);
                    arguments.Add(argument n);


                    backgroundWorker2.RunWorkerAsync(arguments);

private void worker_DoWork(object sender, DoWorkEventArgs e) {

  List<object> genericlist = e.Argument as List<object>;
  extract your multiple arguments from this list and cast them and use them. 

}
Заин Али
источник
@missReclusive приведёт элементы «genericlist», т. е. скажем, «аргумент 1» имеет тип int, а затем int arguments1 = (int) genericlist [0]
Зейн Али
1
это плохая идея с точки зрения обслуживания. Вы должны использовать конкретные типы над List <object>, потому что по крайней мере вы сможете понять, что вы делали (см. Пример в моем ответе ниже)
Денис
Вероятно, я бы предпочел Tuple(или специализированный класс), а не список общих объектов
Джеймс S
6

Проверьте свойство DoWorkEventArgs.Argument :

...
backgroundWorker1.RunWorkerAsync(yourInt);
...

private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
    // Do not access the form's BackgroundWorker reference directly.
    // Instead, use the reference provided by the sender parameter.
    BackgroundWorker bw = sender as BackgroundWorker;

    // Extract the argument.
    int arg = (int)e.Argument;

    // Start the time-consuming operation.
    e.Result = TimeConsumingOperation(bw, arg);

    // If the operation was canceled by the user, 
    // set the DoWorkEventArgs.Cancel property to true.
    if (bw.CancellationPending)
    {
        e.Cancel = true;
    }
}
Джей Риггс
источник
5

Вы можете попробовать это, если хотите передать более одного типа аргументов, сначала добавьте их все в массив типа Object и передайте этот объект в RunWorkerAsync (), вот пример:

   some_Method(){
   List<string> excludeList = new List<string>(); // list of strings
   string newPath ="some path";  // normal string
   Object[] args = {newPath,excludeList };
            backgroundAnalyzer.RunWorkerAsync(args);
      }

Теперь в doWork метод фонового работника

backgroundAnalyzer_DoWork(object sender, DoWorkEventArgs e)
      {
        backgroundAnalyzer.ReportProgress(50);
        Object[] arg = e.Argument as Object[];
        string path= (string)arg[0];
        List<string> lst = (List<string>) arg[1];
        .......
        // do something......
        //.....
       }
sujay
источник
2
+1 Отправка аргументов таким способом также избавляет от необходимости запускать New backgroundworker при каждом запуске, чтобы избежать повторов. (по крайней мере, в моем приложении). Смотрите мой комментарий ниже, связанный с этой проблемой. Также stackoverflow.com/a/12231431/503621 & stackoverflow.com/questions/12507602/…
bshea
4

Вы всегда должны пытаться использовать составной объект с конкретными типами (используя составной шаблон проектирования), а не список типов объектов. Кто бы помнил, какого черта каждый из этих объектов? Подумайте об обслуживании вашего кода позже ... Вместо этого попробуйте что-то вроде этого:

Public (Class or Structure) MyPerson
                public string FirstName { get; set; }
                public string LastName { get; set; }
                public string Address { get; set; }
                public int ZipCode { get; set; }
End Class

А потом:

Dim person as new MyPerson With { .FirstName = Joe”,
                                  .LastName = "Smith”,
                                  ...
                                 }
backgroundWorker1.RunWorkerAsync(person)

а потом:

private void backgroundWorker1_DoWork (object sender, DoWorkEventArgs e)
{
        MyPerson person = e.Argument as MyPerson
        string firstname = person.FirstName;
        string lastname = person.LastName;
        int zipcode = person.ZipCode;                                 
}
Денис
источник