向背景工作者发送参数?


147

假设我想将int参数发送给后台工作者,这如何完成?

private void worker_DoWork(object sender, DoWorkEventArgs e) {

}

我知道什么时候是worker.RunWorkerAsync();,我不知道如何在worker_DoWork中定义它应该采用int参数。

Answers:


235

您可以这样启动:

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

然后

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
我该怎么做两个论点?
sooprise

3
还是发送一个包含多个参数的对象?
sooprise

23
@soo:使用帮助程序类或Tuple<A,B>(C#4 +)(编辑:是,使用对象将其全部打包。例如,参见DoWorkEventArgs self)。
汉克·霍尔特曼

但是,如何将结果通知UI?
rayray,

1
@rayray:,label1.Text = e.Result.ToString();到处我都将其标记为安全。
汉克·霍尔特曼

101

尽管这是一个已经回答的问题,但我还是会提出另一个选择,即IMO更容易阅读:

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

并在处理程序方法上:

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

12
我不知道IMO的意思,我认为这是C#的事情。我用Google搜索“ C#IMO”并降落在这里,得到了答案...大声笑 quantnet.com/threads/cc-vba-or-java.11433
electricalbah

三个参数怎么样?
纪樱2015年

自2012年以来,我不再使用.NET,但如果我没记错的话,您可以添加所需的参数 ... => WorkerDoWork(a, b, c);,只要它与方法签名匹配... WorkerDoWork(int a, string b, string c) {...
即可-dcarneiro

1
请记住,如果您使用了此功能(就像我尝试过的那样),则每次都必须创建一个新的背景工作人员(在您的示例中,您确实如此)。否则,您将遇到和我一样的问题。我的背景工作人员将继续重复之前的运行。如果运行一次就可以了。重复上次运行和当前运行的2次。第三轮将重复最后两个和当前。等
-bshea

但是,该值如何传递到RunWorkerAsync?
CodyBugstein,

47

您可以像这样传递多个参数。

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将“ genericlist”项强制转换,即,假设“ argument 1”是int类型,然后是int arguments1 =(int)genericlist [0]
Zain Ali

1
就维护而言,这是一个坏主意。您应该在List <object>上使用具体类型,因为至少您可以弄清楚自己在做什么(请参见下面我的答案中的示例)
Denis 2015年

我可能更喜欢一个Tuple(或专门的类)而不是一个通用对象列表
James S


6

查看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

如果您想传递不止一种类型的参数,可以尝试一下,首先将它们全部添加到Object类型的数组中,然后将该对象传递给RunWorkerAsync(),这是一个示例:

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

现在在后台工作程序的doWork方法中

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。以这种方式发送自变量也避免了每次运行都必须启动New Backgroundworker以避免重复的情况。(至少在我的应用中)。请参阅以下有关此问题的评论。此外stackoverflow.com/a/12231431/503621stackoverflow.com/questions/12507602/...
bshea


4

您应该始终尝试使用具有具体类型的复合对象(使用复合设计模式),而不是使用对象类型列表。谁会记得这些对象到底是什么?稍后考虑考虑代码的维护...而是尝试如下操作:

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

然后:

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

然后:

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;                                 
}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.