Gửi đối số cho công nhân nền?


147

Giả sử tôi muốn gửi một tham số int cho một nhân viên nền, làm thế nào để thực hiện được điều này?

private void worker_DoWork(object sender, DoWorkEventArgs e) {

}

Tôi biết khi nào đây là worker.RunWorkerAsync ();, Tôi không hiểu cách định nghĩa trong worker_DoWork rằng nó sẽ lấy tham số int.

Câu trả lời:


235

Bạn bắt đầu nó như thế này:

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

và sau đó

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
Làm thế nào tôi có thể làm hai đối số?
bay lên

3
Hay tôi gửi một đối tượng có nhiều hơn một đối số?
bay lên

23
@soo: Sử dụng lớp người trợ giúp hoặc Tuple<A,B>(C # 4 +) (Chỉnh sửa: Có, sử dụng một đối tượng để đóng gói tất cả. Xem ví dụ về bản thân DoWorkEventArss).
Henk Holterman

Nhưng làm thế nào để bạn thông báo cho UI về kết quả?
rayray

1
@rayray : label1.Text = e.Result.ToString();, ở mọi nơi tôi đánh dấu là an toàn.
Henk Holterman

101

Mặc dù đây là một câu hỏi đã được trả lời, tôi sẽ để lại một tùy chọn khác là IMO dễ đọc hơn nhiều:

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

Và về phương pháp xử lý:

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

12
Tôi không biết IMO có nghĩa là gì, tôi nghĩ đó là một thứ C #. Tôi googled "C # IMO" và hạ cánh ở đây và nhận được câu trả lời ... lol quantnet.com/threads/cc-vba-or-java.11433
Electricalbah

Làm thế nào về 3 tham số?
YukiSakura

Tôi không chơi với .NET từ năm 2012, nhưng nếu tôi không nhầm, bạn có thể thêm các tham số bạn muốn ... => WorkerDoWork(a, b, c);miễn là phù hợp với chữ ký phương thức... WorkerDoWork(int a, string b, string c) {...
dcarneiro

1
Hãy ghi nhớ nếu bạn đã sử dụng điều này (như tôi đã cố gắng làm), bạn phải tạo một công cụ nền mới mỗi lần (trong ví dụ của bạn bạn đã làm). Khác bạn sẽ có một vấn đề như tôi đã làm. Trình nền của tôi sẽ tiếp tục lặp lại các lần chạy trước. Nếu chạy một lần thì ổn. 2 lần nó lặp lại lần chạy trước và lần chạy hiện tại. Lần chạy thứ 3 sẽ lặp lại hai lần cuối và hiện tại. vv
bshea

Nhưng làm thế nào để giá trị được truyền vào RunWorkerAsync?
CodyBugstein

47

Bạn có thể vượt qua nhiều đối số như thế này.

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 bỏ các mục "danh sách chung", nghĩa là giả sử "đối số 1" có kiểu int thì int argument1 = (int) genericlist [0]
Zain Ali

1
Đây là một ý tưởng tồi về mặt bảo trì. Bạn nên sử dụng các loại cụ thể trên Danh sách <object> vì ít nhất bạn sẽ có thể tìm ra những gì bạn đang làm (xem một ví dụ trong câu trả lời của tôi dưới đây)
Denis

Có lẽ tôi thích một Tuple(hoặc một lớp chuyên biệt) hơn là một danh sách các đối tượng chung
James S


6

Kiểm tra tài sản DoWorkEventArss.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

bạn có thể thử điều này nếu bạn muốn truyền nhiều hơn một loại đối số, trước tiên hãy thêm tất cả chúng vào một mảng loại Object và chuyển đối tượng đó cho RunWorkerAsync () đây là một ví dụ:

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

Bây giờ trong phương thức doWork của công nhân nền

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. Gửi các đối số theo cách này cũng tránh việc phải bắt đầu một trình xử lý nền mới mỗi lần chạy để tránh lặp lại. (ít nhất là trong ứng dụng của tôi). Xem bình luận của tôi dưới đây liên quan đến vấn đề này. Ngoài ra stackoverflow.com/a/12231431/503621 & stackoverflow.com/questions/12507602/
Đổi


4

Bạn nên luôn luôn cố gắng sử dụng một đối tượng hỗn hợp với các loại cụ thể (sử dụng mẫu thiết kế hỗn hợp) thay vì danh sách các loại đối tượng. Ai sẽ nhớ cái quái gì trong số những đồ vật đó? Hãy suy nghĩ về việc bảo trì mã của bạn sau này ... Thay vào đó, hãy thử một cái gì đó như thế này:

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

Và sau đó:

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

và sau đó:

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;                                 
}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.