调用RunWorkerAsync一次时,会调用BackgroundWorker的DoWork两次?

我在它工作的类中创建了一个后台工作者,但是如果我调用并等到最后一次运行,那么第二次调用它会两次执行相同的过程

我认为bw.DoWork + =有问题

private void button1_Click(object sender, EventArgs e) { nptest.test.start("null", "null"); } namespace nptest { class test { public static void start(string str, string strb) { if (bw.IsBusy != true) { bw.WorkerSupportsCancellation = true; bw.DoWork += (obj, e) => bw_DoWork(str, strb); bw.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bw_RunWorkerCompleted); bw.RunWorkerAsync(); } } private static BackgroundWorker bw = new BackgroundWorker(); private static void bw_DoWork(string str, string strb) { System.Windows.Forms.MessageBox.Show("initializing BackgroundWorker"); } private static void bw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) { if ((e.Cancelled == true)) { Console.WriteLine("Canceled"); } else if (!(e.Error == null)) { Console.WriteLine("Error: " + e.Error.Message); } bw.Dispose(); } } } 

问题解决了

  class test { private static List arguments = new List(); // initializing with program startup public static void bwinitializing() { bw.WorkerSupportsCancellation = true; bw.DoWork += new DoWorkEventHandler(bw_DoWork); bw.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bw_RunWorkerCompleted); } public static void start(string str, string strb) { if (bw.IsBusy != true) { arguments.Clear(); arguments.Add(str); arguments.Add(strb); bw.RunWorkerAsync(arguments); } } private static BackgroundWorker bw = new BackgroundWorker(); private static void bw_DoWork(object sender, DoWorkEventArgs e) { List genericlist = e.Argument as List; System.Windows.Forms.MessageBox.Show("BackgroundWorker " + genericlist[0]); } 

我怀疑无意中添加了多个 DoWork事件。

也就是说, 每次调用start方法时,它都会注册一个新的 DoWork事件处理程序。 这会添加并不会替换现有的处理程序DoWork处理程序。 那么将有多个DoWork处理程序称为后续时间.. 1,2,3等。

 // creates a NEW delegate and adds a NEW handler bw.DoWork += (obj, e) => bw_DoWork(str, strb); 

我建议不要在这里使用闭包,而只是使用一个方法组(隐式转换为委托),然后将数据传递给RunWorkerAsync调用(有一个接受数据参数的表单)。

RunWorkerCompleted +=行没有此问题,因为它从方法组传递委托(保证始终评估为同一委托对象1 )。 因此,对该行的重复+=调用替换处理程序。


例:

 class MyData { public string StrA { get; set; } } // These only need to be setup once (and should be for clarity). // However it will be "ok" now if they are called multiple times // as, since the delegates are the same, the += will // act as a replacement (as it replaces the previous delegate with itself). bw.WorkerSupportsCancellation = true; bw.DoWork += bw_DoWork; bw.RunWorkerCompleted += bw_RunWorkerCompleted; // Pass data via argument bw.RunWorkerAsync(new MyData { StrA = str, }); void bw_DoWork (object sender, DoWorkEventArgs e) { var data = (MyData)e.Argument; var str = data.StrA; // stuff } 

1我不确定它是否保证是引用等于等于,但是使用这种方法允许从方法组的委托中稳定地调用+=-= ,即使通过new DelegateType(MethodGroup)

WRT。 我在主帖中的评论:如果从未创建UI元素的线程访问UI元素,那么将会有趣的“跨线程操作exception”。 我相信消息框的这种用法是“好的”(当不是与另一个线程的所有者一起创建时),但是在BackgroundWorker的DoWork中访问UI的做法通常是可疑的。


另外, 不要在这里调用bw.Dispose() ; 用拥有的容器或上下文处理它。 在这种情况下它似乎很好而且温和,但只有当BGW实例永远不会再次使用时才会这样做。 从事件处理程序调用它也是可疑的,因为BGW仍然“活跃”。

我遇到了与上述评论者“Power-Mosfet”相同的问题

最后,添加一个new BackgroundWorker()然后分配给全局bw值将解决我的问题。

代码是,改为:

 private BackgroundWorker gBgwDownload; private void yourFunction_bw(xxx) { // Create a background thread gBgwDownload.DoWork += bgwDownload_DoWork; gBgwDownload.RunWorkerCompleted += bgwDownload_RunWorkerCompleted; //omited some code gBgwDownload.RunWorkerAsync(paraObj); } 

至:

 private BackgroundWorker gBgwDownload; private void yourFunction_bw(xxx) { // Create a background thread gBgwDownload = new BackgroundWorker(); /* added this line will fix problem */ gBgwDownload.DoWork += bgwDownload_DoWork; gBgwDownload.RunWorkerCompleted += bgwDownload_RunWorkerCompleted; //omited some code gBgwDownload.RunWorkerAsync(paraObj); } 

还有另一个原因。 在其生成的代码中查找DoWorkEventHandler InitializeComponent()如果您通过compnent UI属性生成它并自己注册它。

因为如果你再次注册它将不会覆盖前一个,但会添加另一个事件,并将调用两次。

在我的例子中,BackgroundWorker运行了两次,因为在我的表单的构造函数类中,我声明了DoWork,ProgressChanged和RunWorkerCompleted事件处理程序,但它已经由Visual Studio 2013在此表单类的Designer部分中声明。

所以,我刚刚删除了我的声明,它工作正常。

谢谢….这段代码工作正常…为backroundworker创建新的intance是个好主意….现在我们可以在for / while循环中调用这个函数,并且可以运行多个backgroundworker进程。

按钮点击完成时,我这样编码..没有分配主线程流…多个进程将运行回来….我只是使用消息框弹出..但我们可以做时间过程运行在“ bgwDownload_DoWork“function……将创建多个进程……而且我们不需要检查BackgroundWorker是否忙碌…

 private void button1_Click(object sender, EventArgs e) { for (int i = 0; i < 3; i++) yourFunction_bw(i); } private BackgroundWorker gBgwDownload; private void yourFunction_bw(int i) { // Create a background thread gBgwDownload = new BackgroundWorker(); // added this line will fix problem gBgwDownload.DoWork += bgwDownload_DoWork; gBgwDownload.RunWorkerAsync(i); } private void bgwDownload_DoWork(object sender, DoWorkEventArgs e) { int stre = (int)e.Argument; MessageBox.Show(stre.ToString ()); // time taken process can be added here } 

我今天遇到了这个问题,我把一个后台工作者放在一个执行长时间运行任务的弹出窗口上,当我注意到每次显示表单时,后台工作者RunWorkerCompleted事件被多次调用。

我的问题是我关闭后没有处理该表单,这意味着每次我显示表单时,它每次都会添加另一个处理程序。

完成后处理表格解决了我的问题。 我只想在这里提到它,因为当我为我的情况寻找解决方案时,我遇到了这个页面。