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.