我在它正在运行的类中创建了一个后台工作者,但如果我调用并等到最后一次运行,则第二次调用它将执行相同的过程两次
我认为 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<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]);
}
答案 0 :(得分:16)
我怀疑多个 DoWork
事件被无意添加。
也就是说,每次调用start
方法时,它都会注册 new DoWork
事件处理程序。这个添加并且不替换现有的处理程序DoWork
处理程序。因此,将有多个DoWork
处理程序称为后续时间.. 1,2,3等
// creates a NEW delegate and adds a NEW handler
bw.DoWork += (obj, e) => bw_DoWork(str, strb);
我建议在这里使用闭包 not ,而只是使用一个方法组(隐式转换为委托),然后将数据传递给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元素是从不创建的线程访问的,那么就会有趣的“跨线程操作异常”。我相信消息框的这种用法是“好的”(当不是与另一个线程的所有者一起创建时),但是在BackgroundWorker的DoWork中访问UI的做法通常是可疑的。
此外,不在此致电bw.Dispose()
;将其与拥有的容器或上下文一起处理。在这种情况下它似乎很好而且温和,但只有当BGW实例永远再次使用时才会这样做。从事件处理程序调用它也是可疑的,因为BGW仍然“活跃”。
答案 1 :(得分:13)
我遇到了与上述评论者“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);
}
答案 2 :(得分:5)
还有另一个原因。在其生成的代码DoWorkEventHandler
中查找InitializeComponent()
如果您是通过compnent UI属性生成它并自己注册它。
因为如果你再次注册它,它将不会覆盖前一个,但会添加另一个事件并将调用两次。
答案 3 :(得分:3)
在我的情况下,BackgroundWorker运行了两次,因为在我的表单的构造函数类中,我声明了DoWork,ProgressChanged和RunWorkerCompleted事件处理程序,但它已经由Visual Studio 2013在此表单类的Designer部分中声明。
所以,我刚刚删除了我的声明并且工作正常。
答案 4 :(得分:0)
谢谢....这段代码工作正常......为backroundworker创建新的内容是个好主意.... 现在我们可以在for / while循环中调用这个函数,并且可以运行多个后台工作程序。
我是这样编码的 当按钮点击完成时..没有分配主线程流...多个进程将运行回来.... 我只是使用消息框弹出..但我们可以在“bgwDownload_DoWork”函数中执行时间过程...并且将创建多个进程...而且我们不需要检查BackgroundWorker是否忙碌... < / p>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
}
答案 5 :(得分:0)
今天我遇到了这个问题,我把一个后台工作者放在一个执行长时间运行任务的弹出窗口上,当我注意到每次显示表单时,多次调用后台工作者RunWorkerCompleted事件。
我的问题是我在关闭它之后没有处理该表单,这意味着每次我显示表单时,它都会为每次添加另一个处理程序。
完成后处理表单解决了我的问题。我想在这里提到它,因为当我为我的情况寻找解决方案时,我遇到了这个页面。
答案 6 :(得分:0)
我从设计器中删除了控件,并在代码中实例化了一个新的WorkerProcess:
示例: var bwProcess = new BackgroundWorker();
bwProcess.DoWork + =新的DoWorkEventHandler(bwProcess_DoWork);
bwProcess.RunWorkerCompleted + = bwProcess_RunWorkerCompleted;