Arka Plan Çalışanına Bağımsız Değişkenler mi Gönderiyorsunuz?


150

Diyelim ki arkaplan çalışanına int parametresi göndermek istiyorum, bu nasıl başarılabilir?

private void worker_DoWork(object sender, DoWorkEventArgs e) {

}

Bunun ne zaman worker.RunWorkerAsync (); olduğunu biliyorum, worker_DoWork'te int parametresi alması gerektiğini nasıl tanımlayacağımı anlamıyorum.

Yanıtlar:


239

Bunu şöyle başlatırsın:

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

ve sonra

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
Nasıl iki argüman yapabilirim?
sooprise

3
Yoksa birden fazla argümanla dolu bir nesne mi gönderiyorum?
sooprise

23
@soo: Bir yardımcı sınıf veya bir Tuple<A,B>(C # 4 +) kullanın (Düzen: Evet, hepsini paketlemek için bir nesne kullanın. Örneğin bkz. DoWorkEventArgs self).
Henk Holterman

Ancak sonucu kullanıcı arayüzüne nasıl bildirirsiniz?
rayray

1
@rayray:, label1.Text = e.Result.ToString();bunu güvenli olarak işaretlediğim her yerde.
Henk Holterman

102

Bu zaten cevaplanmış bir soru olsa da, IMO'nun okumasının çok daha kolay olduğu başka bir seçenek bırakıyorum:

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

Ve işleyici yönteminde:

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

12
IMO'nun ne anlama geldiğini bilmiyordum, bunun bir C # şeyi olduğunu düşündüm. Google'da "C # IMO" yazdım
electricbah

3 parametreye ne dersiniz?
YukiSakura

2012'den beri .NET ile oynamıyorum, ancak yanılmıyorsam ... => WorkerDoWork(a, b, c);, yöntem imzasıyla eşleştiği sürece istediğiniz parametreleri ekleyebilirsiniz ... WorkerDoWork(int a, string b, string c) {...
dcarneiro

1
Bunu kullandıysanız (yapmaya çalıştığım gibi), her seferinde yeni bir arka plan çalışanı oluşturmanız gerektiğini unutmayın (örneğinizde yaptınız). Aksi takdirde benim yaptığım gibi bir sorununuz olacak. Arka plan çalışanım önceki çalışmaları tekrar etmeye devam ederdi. Bir kez koşarsan iyiydi. Son çalıştırmayı ve mevcut çalıştırmayı 2 kez tekrarladı. 3. koşu son iki ve şu anki tekrar eder. vb.
bshea

Ancak değer RunWorkerAsync'e nasıl aktarılır?
CodyBugstein

50

Bunun gibi birden çok argüman iletebilirsiniz.

List<object> arguments = new List<object>();
arguments.Add("first");      //argument 1
arguments.Add(new Object()); //argument 2
// ...
arguments.Add(10);           //argument n

backgroundWorker.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" öğelerini çevir, yani "argüman 1" in türünde olduğunu ve sonra int argument1 = (int) genericlist [0]
Zain Ali

2
bu bakım açısından kötü bir fikir. Liste <object> yerine somut türleri kullanmalısınız çünkü en azından ne yaptığınızı anlayabilirsiniz (aşağıdaki
Denis

Muhtemelen Tuplegenel nesnelerin bir listesi yerine bir (veya özel bir sınıfı) tercih ederim
James S


6

DoWorkEventArgs.Argument Özelliğine göz atın :

...
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;
    }
}

6

Birden fazla türde argüman iletmek istiyorsanız, önce hepsini Object türündeki bir diziye ekleyin ve bu nesneyi RunWorkerAsync () öğesine iletin burada bir örnek:

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

Şimdi arka plan çalışanının doWork yönteminde

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. Argümanların bu şekilde gönderilmesi, tekrarları önlemek için her çalıştırmada Yeni bir arka plan çalışanı başlatmak zorunda kalmaz. (en azından benim uygulamamda). Bu sorunla ilgili aşağıdaki yorumuma bakın. Ayrıca stackoverflow.com/a/12231431/503621 & stackoverflow.com/questions/12507602/…
bshea


4

Nesne türleri listesi yerine her zaman somut türlerle (bileşik tasarım desenini kullanarak) bileşik bir nesne kullanmayı denemelisiniz. Bu nesnelerin her birinin ne olduğunu kim hatırlayabilir ki? Kodunuzun bakımını daha sonra düşünün ... Bunun yerine, şuna benzer bir şey deneyin:

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

Ve sonra:

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

ve sonra:

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;                                 
}
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.