Invio di argomenti al lavoratore in background?


147

Diciamo che voglio inviare un parametro int a un lavoratore in background, come può essere realizzato?

private void worker_DoWork(object sender, DoWorkEventArgs e) {

}

So quando questo è worker.RunWorkerAsync () ;, non capisco come definire in worker_DoWork che dovrebbe prendere un parametro int.

Risposte:


235

Lo inizi così:

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

e poi

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
Come posso fare due argomenti?
sooprise,

3
O invio un oggetto pieno di più di un argomento?
sooprise,

23
@soo: usa una classe helper o un Tuple<A,B>(C # 4 +) (Modifica: Sì, usa un oggetto per comprimerlo tutto. Vedi ad esempio DoWorkEventArgs self).
Henk Holterman,

Ma come si comunica all'interfaccia utente del risultato?
Rayray,

1
@rayray: label1.Text = e.Result.ToString();ovunque l'ho contrassegnato come sicuro.
Henk Holterman,

102

Anche se questa è una domanda già risposta, lascerei un'altra opzione che IMO è molto più facile da leggere:

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

E sul metodo del gestore:

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

12
Non sapevo cosa significasse IMO, pensavo fosse una cosa C #. Ho cercato su Google
electricalbah

Che ne dici di 3 parametri?
YukiSakura,

Non gioco con .NET dal 2012, ma se non sbaglio puoi aggiungere i parametri che desideri ... => WorkerDoWork(a, b, c);purché corrispondano alla firma del metodo... WorkerDoWork(int a, string b, string c) {...
dcarneiro,

1
Tieni presente che se lo hai usato (come ho provato a fare), devi creare un nuovo backgroundworker ogni volta (nel tuo esempio l'hai fatto). Altrimenti avrai un problema come ho fatto io. Il mio backgroundworker continuerebbe a ripetere le precedenti esecuzioni. Se eseguito una volta andava bene. 2 volte ha ripetuto l'ultima corsa e la corsa corrente. La terza manche ripeterebbe le ultime due e la corrente. ecc.
bshea,

Ma come viene passato il valore in RunWorkerAsync?
CodyBugstein,

47

Puoi passare più argomenti in questo modo.

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 lancia gli elementi "genericlist", ovvero diciamo che "argomento 1" sia di tipo int quindi int argomento1 = (int) genericlista [0]
Zain Ali,

1
questa è una cattiva idea in termini di manutenzione. Dovresti usare tipi concreti su Elenco <oggetto> perché almeno sarai in grado di capire cosa stavi facendo (vedi un esempio nella mia risposta di seguito)
Denis

Preferirei preferibilmente una Tuple(o una classe specializzata) piuttosto che un elenco di oggetti generici
James S


6

Dai un'occhiata alla proprietà 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

puoi provarlo se vuoi passare più di un tipo di argomenti, prima aggiungili tutti ad una matrice di tipo Object e passa quell'oggetto a RunWorkerAsync () ecco un esempio:

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

Ora nel metodo doWork di lavoratore in background

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. L'invio degli argomenti in questo modo evita anche di dover avviare un nuovo backgroundworker ogni volta per evitare ripetizioni. (almeno nella mia app). Vedi il mio commento qui sotto relativo a questo problema. Anche stackoverflow.com/a/12231431/503621 & stackoverflow.com/questions/12507602/...
bshea


4

Dovresti sempre provare a usare un oggetto composito con tipi concreti (usando un modello di disegno composito) piuttosto che un elenco di tipi di oggetti. Chi ricorderebbe che diamine è ciascuno di quegli oggetti? Pensa alla manutenzione del tuo codice in seguito ... Invece, prova qualcosa del genere:

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

E poi:

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

e poi:

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;                                 
}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.