c#意外的背景员工行为

c#意外的背景员工行为,c#,winforms,backgroundworker,C#,Winforms,Backgroundworker,我在我的主窗体上附加了一个backgroundWorker组件,它运行一个并行任务,为动画gif捕获屏幕。worker函数有一个while循环,它一直运行,直到我在worker上使用CancelAsync(),此时它退出循环,执行一些其他操作,如保存gif文件等,并将一些结果返回到UI线程 private bool capturing = false; public MainForm() { InitializeComponent(); backgroundWorker.DoW

我在我的主窗体上附加了一个backgroundWorker组件,它运行一个并行任务,为动画gif捕获屏幕。worker函数有一个while循环,它一直运行,直到我在worker上使用
CancelAsync()
,此时它退出循环,执行一些其他操作,如保存gif文件等,并将一些结果返回到UI线程

private bool capturing = false;

public MainForm()
{
    InitializeComponent();
    backgroundWorker.DoWork += backgroundWorker_DoWork;
    backgroundWorker.RunWorkerCompleted += backgroundWorker_RunWorkerCompleted;
    backgroundWorker.WorkerSupportsCancellation = true;
}

private void captureBtn_Click(object sender, EventArgs e)
{
    Debug.WriteLine("Button clicked");
    if (capturing) { return; }
    if (!backgroundWorker.IsBusy)
    {
        backgroundWorker.RunWorkerAsync();
    }
}

private void stopCaptureBtn_Click(object sender, EventArgs e)
{
    if (backgroundWorker.IsBusy)
    {
        backgroundWorker.CancelAsync();
    }
}

private void backgroundWorker_DoWork(object sender, System.ComponentModel.DoWorkEventArgs e)
{
    capturing = true;
    Debug.WriteLine("DoWork running");

    while (!backgroundWorker.CancellationPending)
    {
        Debug.WriteLine("Capturing frame {0}", frames);
        //do the capturing to memory stream
    }

    Debug.WriteLine("DoWork cancelled");

    //do some other things like saving the gif etc
    e.Result = someResult;
}

private void backgroundWorker_RunWorkerCompleted(object sender, System.ComponentModel.RunWorkerCompletedEventArgs e)
{
    Debug.WriteLine("RunWorkerCompleted running");
    capturing = false;
    //does something with the e.Result
}
在正常测试期间,我的控制台输出如下:

Button clicked
DoWork running
Capturing frame 0
Capturing frame 1
Capturing frame 2
Capturing frame 3
Capturing frame 4
Capturing frame 5
Cancel button clicked
DoWork cancelled
The thread 0x2e4c has exited with code 0 (0x0).
DoWork running
DoWork cancelled
The thread 0x1010 has exited with code 0 (0x0).
RunWorkerCompleted running

该函数似乎运行了两次,我可以看到两个独立的线程退出,而且我似乎没有从捕获中得到任何结果。如果我在backgroundWorker_DoWork函数中设置了一个断点并在以后继续,那么第一次运行会正常进行捕获。可能发生了什么?

线程0x3108已退出,代码为0(0x0),表示没有错误。 在阅读或编写大数据时,你应该将其分成几个部分。否则,你就无法前进。当前while循环在写入内存流时被禁用。 因此,您的backgroundWorker_DoWork方法应如下所示:

    private void backgroundWorker_DoWork(object sender, DoWorkEventArgs e)
    {
        var worker = (BackgroundWorker)sender;

        // this is an example file
        string filePath = @"C:\file.gif";

        // it determines how many bytes of data will be received from the stream each time.
        byte[] buffer = new byte[4096];
        int byteCount = 0;

        // we are preparing to read stream.
        using (FileStream fs = new FileStream(filePath, FileMode.Open, System.IO.FileAccess.Read))
        using (MemoryStream ms = new MemoryStream())
        {
            // read the stream bytes and fill buffer
            while ((byteCount = fs.Read(buffer, 0, buffer.Length)) > 0)
            {
                // if the task was canceled
                if (worker.CancellationPending)
                {
                    e.Cancel = true;
                    break;
                }

                // write buffer to memory stream
                ms.Write(buffer, 0, byteCount);
            }
        }
    }

它被调用了两次,因为在InitializeComponent()之后第二次绑定事件。 只需对这些行进行注释,就可以了。 下面是相同的示例,没有运行两次的问题

样本输出 ... ... ... 捕获帧2632 捕获帧2633 捕获帧2634 取消嫁妆 RunWorker完成运行

public partial class Form1 : Form
    {
        private bool capturing = false;
        public Form1()
        {
            InitializeComponent();
            backgroundWorker1.WorkerSupportsCancellation = true;

  // Don't need to re-bind
            //backgroundWorker1.DoWork += backgroundWorker1_DoWork;
            //backgroundWorker1.RunWorkerCompleted += backgroundWorker1_RunWorkerCompleted;
            //backgroundWorker1.WorkerSupportsCancellation = true;
        }



private void captureBtn_Click(object sender, EventArgs e)
        {
            Debug.WriteLine("Button clicked");
            if (capturing) { return; }
            if (!backgroundWorker1.IsBusy)
            {
                backgroundWorker1.RunWorkerAsync();
            }
        }

        private void stopCaptureBtn_Click(object sender, EventArgs e)
        {
            if (backgroundWorker1.IsBusy)
            {
                backgroundWorker1.CancelAsync();
            }
        }

        private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
        {
            capturing = true;
            Debug.WriteLine("DoWork running");
            int frames = 1;

            while (!backgroundWorker1.CancellationPending)
            {
                Debug.WriteLine("Capturing frame {0}", frames);
                //do the capturing to memory stream
                frames++;
            }

            Debug.WriteLine("DoWork cancelled");

            //do some other things like saving the gif etc
            //e.Result = someResult;
        }

        private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            Debug.WriteLine("RunWorkerCompleted running");
            capturing = false;
            //does something with the e.Result
        }


在那里声明一个额外的变量bool。在
backgroundWorker\u DoWork
中将其设置为true,然后在
backgroundWorker\u RunWorkerCompleted
中将其设置为false。然后在启动工作程序之前,在
captureBtn_单击
例行程序中检查此项。这会有帮助吗,我有一种感觉,快速双击或者发生了什么事情,或者其他一些可能被你的帖子遗漏的事情。行为完全相同。我还检查了
captureBtn\u Click
似乎只运行了一次。我还注意到
backgroundWorker\u RunWorkerCompleted
只在底部运行。正如RunWorkerCompleted的名称所示:它在完成工作时运行。你能告诉我们那个的密码吗?我在你的问题中没有看到。我用新的调试帖子和缺少的函数更新了我的代码。这确实是问题所在。在表单中创建工人时,我没有意识到嫁妆已经绑定。