关闭表单时如何在中间取消backgroundworker操作?

How do i cancel backgroundworker operation in the middle when closing the form?

我有这个 DoWork 事件代码:

private void backgroundWorker2_DoWork(object sender, DoWorkEventArgs e)
        {
            BackgroundWorker bgw = (BackgroundWorker)sender;
            if (bgw.CancellationPending == true)
            {
                return;
            }
            else
            {
            Bitmap newbmp = new Bitmap(512, 512);
            IEnumerable<Point> CommonList = null;
            StreamWriter w = new StreamWriter(@"c:\diff\diff.txt");
            pixelscoordinatesinrectangle = new List<Point>();
            pixelscoordinatesinrectangle = pointsAffected.ToList();
            DrawIt = false;
            for (int i = 0; i < trackBar1FileInfo.Length; i++)
            {
                DrawIt = true;
                trackBar1.Invoke(new MethodInvoker(delegate { trackBar1.Value = i; }));


                        timer1.Stop();
                        Button1Code();
                        timer1.Start();
                        trackBar2.Invoke(new MethodInvoker(delegate { trackBar2.Enabled = false; }));
                        trackBar1.Invoke(new MethodInvoker(delegate { trackBar1.Enabled = false; }));
                        trackBar1.Invoke(new MethodInvoker(delegate { LoadPictureAt(trackBar1.Value, sender); }));
                        pictureBox1.Load(trackBar1FileInfo[i].FullName);
                        trackBar1.Invoke(new MethodInvoker(delegate {
                            ConvertedBmp = ConvertTo24(trackBar1FileInfo[trackBar1.Value].FullName);
                        }));

                    ConvertedBmp.Save(ConvertedBmpDir + "\ConvertedBmp.bmp");
                    mymem = ToStream(ConvertedBmp, ImageFormat.Bmp);
                    Button1Code();

                    pictureBox1.Invoke(new MethodInvoker(delegate { pictureBox1.Refresh(); }));                    
                    newpixelscoordinates = new List<Point>();
                    newpixelscoordinates = pointsAffected.ToList();
                    CommonList = pixelscoordinatesinrectangle.Intersect(newpixelscoordinates);
                    foreach (Point s in CommonList)
                    {
                        w.WriteLine("The following points are the same" + s);
                        newbmp.SetPixel(s.X, s.Y, Color.Red);
                    }
                }
                w.Close();
                using (Graphics G = Graphics.FromImage(newbmp))
                newbmp.Save(@"c:\newbmp\newbmp.bmp", ImageFormat.Bmp);
                newbmp.Dispose();
            }
        }

问题是当 backgroundworker dowork 正在工作时,我在中间关闭了表单。 然后它每次都在 DoWork 事件异常的不同行上抛出:

无法访问已释放的对象

例如这一行:

trackBar1.Invoke(new MethodInvoker(delegate { trackBar1.Value = i; }));

我尝试在 FormClosing 事件中执行以下操作:

backgroundWorker2.CancelAsync();

但它什么也没做。

我已经在设计器中将 backgroundworker2 WorkerSupportsCancellation 设置为 true。

在循环中我试着这样做:

pictureBox1.Invoke(new MethodInvoker(delegate { pictureBox1.Refresh();
                    if (bgw.CancellationPending == true)
                    {
                        MessageBox.Show("cancelled");
                    }

                    }));

但我仍然没有收到异常消息:无法访问已处置的对象

尝试在循环之前和循环顶部添加此 bgw.CancellationPending 检查。在循环的每个地方我都在使用 Begin Invoke

但仍然在循环内的不同行上始终遇到此异常。

在我做的表格关闭事件中:

private void ScanClouds_FormClosing(object sender, FormClosingEventArgs e)
        {

            backgroundWorker2.WorkerSupportsCancellation = true;
            backgroundWorker2.CancelAsync();
        }

而且在关闭表单时我仍然遇到异常。

您只在 DoWork 代码中检查 bgw.CancellationPending == true 一次。您需要检查 每次 您从某个可以 "take a while" 的操作返回,例如,在您的每个 Invoke 调用之后(这可能是一个很好的尝试将其中一些组合成一个 Invoke 并在每次调用中做不止一件事的想法)

注意设置这个标志

bgw.CancellationPending = true 

仅通知工作线程已请求取消。在 DoWork 中的线程检查此 bgw.CancellationPending 标志之前,实际上不会发生取消。

所以你需要检查你的循环

for (int i = 0; i < trackBar1FileInfo.Length; i++)
{
    if(bgw.CancellationPending == false) 
     {
       //...
     }
}