BackgroundWorker 不会在 CancelAsync() 上停止并且只工作一次

BackgroundWorker does not stop on CancelAsync() and works only once

我有一种叫做 Sorter 的表格。上面有按钮 'jademy' 打开 window 'Progress Window'

private void jademy_Click(object sender, EventArgs e)
{
    ProgressWindow progress = new ProgressWindow();
    progress.ShowDialog();
}

'Progress Window' 表单代码如下:

public partial class ProgressWindow : Form
{
    private BackgroundWorker backgroundWorker = new BackgroundWorker();

    public ProgressWindow()
    {
        InitializeComponent();
        stop.Visible = true;
        ok.Visible = false;
        backgroundWorker.RunWorkerAsync();
        backgroundWorker.WorkerReportsProgress = true;
        backgroundWorker.WorkerSupportsCancellation = true;

        #region block1

        backgroundWorker.DoWork += new DoWorkEventHandler(backgroundWorker_DoWork);
        backgroundWorker.ProgressChanged += new ProgressChangedEventHandler(backgroundWorker_ProgressChanged);
        backgroundWorker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(backgroundWorker_RunWorkerCompleted);

        #endregion
    }

    private void stop_Click(object sender, EventArgs e)
    {
        backgroundWorker.CancelAsync();
    }

    private void ok_Click(object sender, EventArgs e)
    {
        this.Close();
    }

    private void backgroundWorker_DoWork(object sender, DoWorkEventArgs e)
    {
        for (int i = 1; i <= 100; i++)
        {
            Thread.Sleep(100);
            backgroundWorker.ReportProgress(i);
        }

    }

    private void backgroundWorker_ProgressChanged(object sender, ProgressChangedEventArgs e)
    {
        progressBar1.Value = e.ProgressPercentage;
        this.Text = "Done: " + e.ProgressPercentage.ToString() + "%";
    }

    private void backgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
    {
        if ((e.Cancelled == true))
        {
            MessageBox.Show("Cancelled", "Message", MessageBoxButtons.OKCancel, MessageBoxIcon.Asterisk);
        }

        else if (!(e.Error == null))
        {
            MessageBox.Show("Error: " + e.Error.Message, "ERROR!", MessageBoxButtons.OKCancel);
        }
        else
        {
            ok.Visible = true;
            stop.Visible = false;
        }
    }
}

现在。我有三个问题。

  1. 点击停止按钮没有任何反应。 'backgroundWorker.CancelAsync()' 似乎没有停止进程。

  2. 当我关闭进度 window 并且我想再次 运行 它时,我必须等待一段时间才能单击 'jademy' 按钮。否则进度 window 显示如下: (and nothing changes) instead of this: 程序 "remembers" 看起来工作已经完成,即使它是 ProgressWindow 的新实例。请注意,在不正确的版本上 'OK' 按钮立即可见 - 而不是等待工作完成。

  3. 我想澄清一下"block 1"中的代码。老实说,我并不完全理解。这部分真的必不可少吗?我的意思是,我发现了很多例子(也在这个论坛上 - 例如 here),其中没有包括这部分,用户报告说该解决方案有效。就我而言,没有这部分进度条根本不起作用,但也许我做错了什么。

  1. 调用 CancelAsync 会停止所有挂起的工作。但如果工作已经开始,则方法体需要检查是否调用了取消。参见 CancelAsync

CancelAsync submits a request to terminate the pending background operation and sets the CancellationPending property to true.

When you call CancelAsync, your worker method has an opportunity to stop its execution and exit. The worker code should periodically check the CancellationPending property to see if it has been set to true.

  1. 我不知道。顺便说一下,图像不起作用。将其嵌入问题中。
  2. 代码分配了一个方法,该方法在 BackgroundWorker 启动时执行,您连接方法以报告进度并在后台工作完成后进行清理/更新。

BackgroundWorker.CancelAsync 经常被误解。它 不会停止任何待处理的工作 而只是向 UI 线程发出工作已被取消的信号!它只是设置 CancellationPending 属性,您可以定期在 DoWork 中轮询。

不幸的是,在 DoWork 中调用 Thread.Sleep 的 MSDN 示例非常愚蠢。通常你在 DoWork 中调用阻塞操作,它通常是完全 UI-独立的。

查看我的回答 here 以获得更有用的示例。

1。 根据 MSDN BackgroundWorker Class page,也许你应该在循环中添加一个中断。

    private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
    {
        BackgroundWorker worker = sender as BackgroundWorker;

        for (int i = 1; i <= 10; i++)
        {
            if (worker.CancellationPending == true)
            {
                e.Cancel = true;
                break;
            }
            else
            {
                // Perform a time consuming operation and report progress.
                System.Threading.Thread.Sleep(500);
                worker.ReportProgress(i * 10);
            }
        }
    }

2。 不知道。

3。 块 1 区域正在为 BackgroundWorker 事件设置。在我的例子中,如果我点击属性中的闪电图标来设置事件,它通常会出现在Form1.Designer.cs。