Envoi d'arguments à l'agent d'arrière-plan?

147

Disons que je veux envoyer un paramètre int à un travailleur d'arrière-plan, comment cela peut-il être accompli?

private void worker_DoWork(object sender, DoWorkEventArgs e) {

}

Je sais quand il s'agit de worker.RunWorkerAsync () ;, Je ne comprends pas comment définir dans worker_DoWork qu'il devrait prendre un paramètre int.

sooprise
la source

Réponses:

235

Vous démarrez comme ceci:

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

puis

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.
}
Henk Holterman
la source
38
Comment puis-je faire deux arguments?
sooprise le
3
Ou dois-je envoyer un objet contenant plus d'un argument?
sooprise le
23
@soo: Utilisez une classe d'assistance ou un Tuple<A,B>(C # 4 +) (Edit: Oui, utilisez un objet pour tout emballer. Voir par exemple DoWorkEventArgs self).
Henk Holterman le
Mais comment notifier l'interface utilisateur du résultat?
rayray
1
@rayray:, label1.Text = e.Result.ToString();partout j'ai marqué cela comme sûr.
Henk Holterman
102

Même s'il s'agit d'une question déjà répondue, je laisserais une autre option que l'OMI est beaucoup plus facile à lire:

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

Et sur la méthode du gestionnaire:

private void WorkerDoWork(int value, string text) {
    ...
}
dcarneiro
la source
12
Je ne savais pas ce que voulait dire IMO, je pensais que c'était une chose C #. J'ai cherché sur Google "C # IMO" et j'ai atterri ici et j'ai obtenu la réponse ... lol quantnet.com/threads/cc-vba-or-java.11433
electricbah
Que diriez-vous de 3 paramètres?
YukiSakura
Je ne joue pas avec .NET depuis 2012, mais si je ne me trompe pas, vous pouvez ajouter les paramètres que vous voulez ... => WorkerDoWork(a, b, c);tant qu'ils correspondent à la signature de la méthode... WorkerDoWork(int a, string b, string c) {...
dcarneiro
1
Gardez à l'esprit que si vous avez utilisé cela (comme j'ai essayé de le faire), vous devez créer un nouveau travailleur d'arrière-plan à chaque fois (dans votre exemple, vous l'avez fait). Sinon, vous aurez un problème comme moi. Mon backgroundworker continuerait à répéter les exécutions précédentes. Si courir une fois, c'était bien. 2 fois il a répété la dernière exécution et la course actuelle. La troisième manche répéterait les deux derniers et actuels. etc.
bshea
Mais comment la valeur est-elle transmise à RunWorkerAsync?
CodyBugstein
47

Vous pouvez passer plusieurs arguments comme celui-ci.

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. 

}
Zain Ali
la source
@missReclusive lance les éléments "genericlist", c'est-à-dire, disons que "argument 1" est de type int puis int argument1 = (int) genericlist [0]
Zain Ali
1
c'est une mauvaise idée en termes de maintenance. Vous devriez utiliser des types concrets sur List <object> car au moins vous serez en mesure de comprendre ce que vous faisiez (voir un exemple dans ma réponse ci-dessous)
Denis
Je préférerais probablement une Tuple(ou une classe spécialisée) plutôt qu'une liste d'objets génériques
James S
6

Découvrez la propriété 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;
    }
}
Jay Riggs
la source
5

vous pouvez essayer ceci si vous voulez passer plus d'un type d'arguments, ajoutez-les d'abord tous à un tableau de type Object et passez cet objet à RunWorkerAsync () voici un exemple:

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

Maintenant dans la méthode doWork de background worker

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
la source
2
+1. Envoyer les arguments de cette manière évite également d'avoir à démarrer un nouveau backgroundworker à chaque exécution pour éviter les répétitions. (au moins dans mon application). Voir mon commentaire ci-dessous lié à ce problème. Aussi stackoverflow.com/a/12231431/503621 & stackoverflow.com/questions/12507602/…
bshea
4

Vous devez toujours essayer d'utiliser un objet composite avec des types concrets (en utilisant un modèle de conception composite) plutôt qu'une liste de types d'objets. Qui se souviendrait de ce qu'est diable chacun de ces objets? Pensez à la maintenance de votre code plus tard ... Essayez plutôt quelque chose comme ceci:

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

Puis:

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

puis:

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;                                 
}
Denis
la source