Надсилання аргументів фоновому працівникові?


147

Скажімо, я хочу надіслати параметр int до фонового працівника, як це можна зробити?

private void worker_DoWork(object sender, DoWorkEventArgs e) {

}

Я знаю, коли це робочий.RunWorkerAsync ();, я не розумію, як визначити в Working_DoWork, що він повинен приймати параметр int.

Відповіді:


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
Або я надсилаю об'єкт, наповнений більш ніж одним аргументом?
приспів

23
@soo: Використовуйте хелперний клас або Tuple<A,B>(C # 4 +) (Редагувати: Так, використовуйте об'єкт, щоб запакувати все це. Див., наприклад, DoWorkEventArgs self).
Хенк Холтерман

Але як ви сповіщаєте інтерфейс користувача про результат?
rayray

1
@rayray:, label1.Text = e.Result.ToString();скрізь я позначав це як безпечне.
Хенк Холтерман

101

Незважаючи на те, що це вже відповів на запитання, я б залишив інший варіант, що IMO читати набагато простіше:

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

І про метод обробника:

private void WorkerDoWork(int value, string text) {
    ...
}

12
Я не знав, що означає ІМО, я подумав, що це C # річ. Я гуглив "C # IMO" і приземлився тут, і отримав відповідь ... lol quantnet.com/threads/cc-vba-or-java.11433
electricbah

Як щодо 3 параметрів?
YukiSakura

Я не граю з .NET з 2012 року, але якщо я не помиляюся, ви можете додати потрібні параметри до ... => WorkerDoWork(a, b, c);тих пір, поки це відповідає підпису методу... WorkerDoWork(int a, string b, string c) {...
dcarneiro

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 argument1 = (int) genericlist [0]
Zain Ali

1
це погана ідея в плані технічного обслуговування. Ви повинні використовувати конкретні типи у списку <об’єкт>, оскільки принаймні ви зможете розібратися, що ви робили (див. Приклад у моїй відповіді нижче)
Денис,

Я, мабуть, вважаю за краще 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......
        //.....
       }

2
+1. Передача аргументів таким чином також дозволяє уникнути необхідності кожного запуску нового робочого фону, щоб уникнути повторів. (принаймні в моєму додатку). Дивіться мій коментар нижче щодо цієї проблеми. Також 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;                                 
}
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.