C# 当 RunWorkerAsync 被调用一次时,BackgroundWorker 的 DoWork 被调用两次?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/12231379/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
DoWork of BackgroundWorker is called twice when RunWorkerAsync is called once?
提问by hlatif
I have create a backgroundworker in an class it works, but if i call and wait until the end run, call it for the second time it will do the same process twice
我在一个可以工作的类中创建了一个后台工作程序,但是如果我调用并等到最后运行,第二次调用它它会执行两次相同的过程
i thinks there is somthing wrong with bw.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();
}
}
}
problem solved
问题解决了
class test
{
private static List<object> arguments = new List<object>();
// 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<object> genericlist = e.Argument as List<object>;
System.Windows.Forms.MessageBox.Show("BackgroundWorker " + genericlist[0]);
}
采纳答案by crifan
I have encounter same problem as above commenter "Power-Mosfet"
我遇到了与上述评论者“Power-Mosfet”相同的问题
and in the end, added a new BackgroundWorker()then assigned to the global bw value will fix my problem.
最后,添加一个new BackgroundWorker()然后分配给全局 bw 值将解决我的问题。
code is, change from:
代码是,从:
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);
}
to:
到:
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);
}
回答by hlatif
I would suspect that multipleDoWorkevents are being inadvertently added.
我怀疑无意中添加了多个DoWork事件。
That is, every timethe startmethod is called it registers a newDoWorkevent handler. This addsand does not replacethe existing handler DoWorkhandler. So then there will be multiple DoWorkhandlers called subsequent times .. 1, 2, 3, etc.
也就是说,每次start调用该方法时,它都会注册一个新的DoWork事件处理程序。这会添加而不是替换现有的处理DoWork程序处理程序。那么会有多个DoWork处理程序调用后续时间.. 1, 2, 3 等。
// creates a NEW delegate and adds a NEW handler
bw.DoWork += (obj, e) => bw_DoWork(str, strb);
I would recommend notusing a closure here, but rather just use a Method Group (with implicit conversion to a delegate) and then pass the data to the RunWorkerAsynccall (there is a form that takes an argument for data).
我建议不要在这里使用闭包,而只是使用方法组(隐式转换为委托),然后将数据传递给RunWorkerAsync调用(有一个表单,它接受数据的参数)。
The RunWorkerCompleted +=line doesn't have this issue because it is passed a delegate from a Method Group (which is guaranteed to always evaluate to the same delegate object1). Thus the repeated +=calls for that line willreplace the handler.
该RunWorkerCompleted +=行没有这个问题,因为它从方法组传递了一个委托(保证总是评估为相同的委托对象1)。因此+=,对该行的重复调用将替换处理程序。
Example:
例子:
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
}
1I am not sure if it is guaranteed to be reference-equals equality, but using this approach allows for stable invoking of +=and -=from the delegate from the Method Group even if obtained by new DelegateType(MethodGroup).
1,我不知道这是否是保证引用等于平等,但使用这种方法允许稳定的调用+=,并-=从方法组,即使所获得的代表new DelegateType(MethodGroup)。
Wrt. my comment in the main post: if UI elements are accessed from a thread on which they were notcreated then there will fun "Cross-thread operation exceptions". I believe this usage of a Message Box is "okay" (when not created with an owner from another thread), but the practice of accessing the UI in a BackgroundWorker's DoWork is generally dubious.
写的。我在主帖中的评论:如果从未创建UI 元素的线程访问 UI 元素,那么将会出现有趣的“跨线程操作异常”。我相信消息框的这种用法是“好的”(当不是使用来自另一个线程的所有者创建时),但在 BackgroundWorker 的 DoWork 中访问 UI 的做法通常是可疑的。
Also, do notcall bw.Dispose()here; dispose it with the owning container or context. It appears to be nice and benign in this case, but only do it when that BGW instance will neverbe used again. Calling it from an event handler is also dubious as the BGW is still "active".
另外,不要bw.Dispose()在这里打电话;使用拥有的容器或上下文来处理它。在这种情况下,它看起来不错且良性,但只有在该 BGW 实例将不再被使用时才这样做。从事件处理程序调用它也是可疑的,因为 BGW 仍然是“活动的”。
回答by Dharani
thank you....this code is working fine... creating new intance for backroundworker is good idea.... Now we can call this function in for/while loop and can run multiple backgroundworker process.
谢谢....这段代码工作正常...为backroundworker创建新的实例是个好主意....现在我们可以在for/while循环中调用这个函数并且可以运行多个backgroundworker进程。
I coded like this when button click is done.. without distrubting the main thread flow... multiple process will be running back side.... i just used messagebox to pop up..but we can do timetaking process to run in "bgwDownload_DoWork" function... and multiple process will be created... and her we need not check the BackgroundWorker is busy or not...
当按钮点击完成时,我像这样编码.. 不破坏主线程流......多个进程将在后台运行......我只是使用消息框弹出......但我们可以做一些耗时的过程来运行“ bgwDownload_DoWork" 函数......并且将创建多个进程......她我们不需要检查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
}
回答by kingkeamo
I ran into this problem today, I put a background worker on a popup form that was doing a long running task when I noticed that every time I showed the form the background worker RunWorkerCompleted event was being called multiple times.
我今天遇到了这个问题,当我注意到每次显示表单时,后台工作人员 RunWorkerCompleted 事件都被多次调用时,我将一个后台工作人员放在一个执行长时间运行任务的弹出窗体上。
My problem was that I was not disposing of the form after closing it, which meant every time I showed the form it added another handler to the even each time.
我的问题是我没有在关闭表单后处理它,这意味着每次我显示表单时,它都会向偶数添加另一个处理程序。
Disposing of the form when finished with it solved my problem. Just wanted to mention it here as I came across this page when I went looking for a solution for my situation.
完成后处理表格解决了我的问题。当我为我的情况寻找解决方案时,我遇到了这个页面,只是想在这里提一下。
回答by AZ_
There is also another reason. look for DoWorkEventHandlerin its generated code InitializeComponent()If you have generated it through compnent UI properties and also registering it yourself.
还有一个原因。DoWorkEventHandler在其生成的代码中查找InitializeComponent()如果您是通过组件 UI 属性生成它并自己注册的。
Because if you register it again it will not override the previous one but will add another event and will call twice.
因为如果您再次注册它,它不会覆盖前一个,而是会添加另一个事件并会调用两次。
回答by Sergio Chaves
In my case, BackgroundWorker was running twice because in the constructor class of my form I declared the DoWork, ProgressChanged and RunWorkerCompleted event handlers, but it was already declared by Visual Studio 2013 in Designer part of this form class.
就我而言,BackgroundWorker 运行了两次,因为在我的表单的构造函数类中我声明了 DoWork、ProgressChanged 和 RunWorkerCompleted 事件处理程序,但它已经由 Visual Studio 2013 在此表单类的设计器部分中声明。
So, I just deleted my declarations and it worked fine.
所以,我只是删除了我的声明,它工作正常。
回答by Amir
I removed the control from the designer and instantiate a new WorkerProcess in Code:
我从设计器中删除了控件并在代码中实例化了一个新的 WorkerProcess:
example: var bwProcess = new BackgroundWorker();
示例: var bwProcess = new BackgroundWorker();
bwProcess.DoWork += new DoWorkEventHandler(bwProcess_DoWork);
bwProcess.DoWork += new DoWorkEventHandler(bwProcess_DoWork);
bwProcess.RunWorkerCompleted += bwProcess_RunWorkerCompleted;
bwProcess.RunWorkerCompleted += bwProcess_RunWorkerCompleted;

