Argumente an Hintergrundarbeiter senden?

147

Angenommen, ich möchte einen int-Parameter an einen Hintergrundarbeiter senden. Wie kann dies erreicht werden?

private void worker_DoWork(object sender, DoWorkEventArgs e) {

}

Ich weiß, wann dies worker.RunWorkerAsync (); ist. Ich verstehe nicht, wie man in worker_DoWork definiert, dass es einen int-Parameter annehmen soll.

Sooprise
quelle

Antworten:

235

Sie starten es so:

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

und dann

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
quelle
38
Wie kann ich zwei Argumente vorbringen?
Sooprise
3
Oder sende ich ein Objekt mit mehr als einem Argument?
Sooprise
23
@soo: Verwenden Sie eine Hilfsklasse oder eine Tuple<A,B>(C # 4 +) (Bearbeiten: Ja, verwenden Sie ein Objekt, um alles einzupacken. Siehe zum Beispiel DoWorkEventArgs self).
Henk Holterman
Aber wie benachrichtigen Sie die Benutzeroberfläche über das Ergebnis?
Rayray
1
@rayray: label1.Text = e.Result.ToString();Überall habe ich das als sicher markiert.
Henk Holterman
101

Obwohl dies eine bereits beantwortete Frage ist, würde ich eine andere Option belassen, die IMO viel einfacher zu lesen ist:

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

Und zur Handler-Methode:

private void WorkerDoWork(int value, string text) {
    ...
}
dcarneiro
quelle
12
Ich wusste nicht, was IMO bedeutet, ich dachte, es sei eine C # -Sache. Ich googelte "C # IMO" und landete hier und bekam die Antwort ... lol quantnet.com/threads/cc-vba-or-java.11433
electricbah
Wie wäre es mit 3 Parametern?
YukiSakura
Ich spiele seit 2012 nicht mehr mit .NET, aber wenn ich mich nicht irre, können Sie die gewünschten Parameter hinzufügen, ... => WorkerDoWork(a, b, c);solange sie mit der Methodensignatur ... WorkerDoWork(int a, string b, string c) {...
übereinstimmen
1
Denken Sie daran, wenn Sie dies verwendet haben (wie ich es versucht habe), müssen Sie jedes Mal einen neuen Hintergrundarbeiter erstellen (in Ihrem Beispiel haben Sie dies getan). Sonst haben Sie ein Problem wie ich. Mein Hintergrundarbeiter würde die vorherigen Läufe immer wieder wiederholen. Wenn einmal ausgeführt, war es in Ordnung. 2 Mal wurde der letzte und der aktuelle Lauf wiederholt. Der dritte Lauf würde die letzten beiden und aktuellen wiederholen. usw.
bshea
Aber wie wird der Wert an RunWorkerAsync übergeben?
CodyBugstein
47

Sie können mehrere Argumente wie folgt übergeben.

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
quelle
@missReclusive Cast die "genericlist" Elemente, dh sagen wir "Argument 1" ist vom Typ int, dann int argument1 = (int) genericlist [0]
Zain Ali
1
Dies ist eine schlechte Idee in Bezug auf die Wartung. Sie sollten konkrete Typen über List <Objekt> verwenden, da Sie zumindest herausfinden können, was Sie getan haben (siehe ein Beispiel in meiner Antwort unten)
Denis
Ich würde wahrscheinlich eher eine Tuple(oder eine spezialisierte Klasse) als eine Liste allgemeiner Objekte bevorzugen
James S
6

Überprüfen Sie die DoWorkEventArgs.Argument-Eigenschaft :

...
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
quelle
5

Sie können dies ausprobieren, wenn Sie mehr als einen Argumenttyp übergeben möchten. Fügen Sie zunächst alle zu einem Array vom Typ Object hinzu und übergeben Sie dieses Objekt an RunWorkerAsync (). Hier ein Beispiel:

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

Jetzt in der doWork-Methode des Hintergrundarbeiters

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
quelle
2
+1. Durch das Senden der Argumente auf diese Weise wird auch vermieden, dass bei jedem Lauf ein neuer Hintergrundarbeiter gestartet werden muss, um Wiederholungen zu vermeiden. (zumindest in meiner App). Siehe meinen Kommentar unten zu diesem Problem. Auch stackoverflow.com/a/12231431/503621 & stackoverflow.com/questions/12507602/…
bshea
4

Sie sollten immer versuchen, ein zusammengesetztes Objekt mit konkreten Typen (unter Verwendung eines zusammengesetzten Entwurfsmusters) anstelle einer Liste von Objekttypen zu verwenden. Wer würde sich daran erinnern, was zum Teufel jedes dieser Objekte ist? Denken Sie später über die Wartung Ihres Codes nach ... Versuchen Sie stattdessen Folgendes:

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

Und dann:

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

und dann:

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
quelle