Backgroundworker.CancelAsync()不起作用

gan*_*ers 4 c# backgroundworker

我有一个运行单个进程的后台工作程序.我希望能够在它进行时取消处理,但是当我调用CancelAsync()方法时,它实际上从未取消.我哪里错了?

这是DoWork()方法:

        private void bgw_DoWork(object sender, DoWorkEventArgs e)
    {
        BackgroundWorker b = sender as BackgroundWorker;

        if (b != null)
        {
             if (!b.CancellationPending)
            {
                try
                {
                    // Let's run the process as a backgroundworker so we have the ability to cancel the search, and/or be able to view results while it's still searching
                    ProcessParameters pp = e.Argument as ProcessParameters;

                    if (pp.DoReplace)
                        results = FindReplace.FindReplace.FindAndReplace(pp.PathToSearch, pp.FindText, pp.ReplaceText, pp.UseRegularExpressions, pp.IncludeList, pp.ExcludeList, pp.RecurseSubdirectories, pp.IgnoreCase);
                    else
                        results = FindReplace.FindReplace.Find(pp.PathToSearch, pp.FindText, pp.UseRegularExpressions, pp.IncludeList, pp.ExcludeList, pp.RecurseSubdirectories, pp.IgnoreCase);
                }
                catch (Exception ex)
                {
                    MessageBox.Show(ex.ToString());
                }
            }
            else
            {
                // Cancel was clicked
                e.Cancel = true;
            }
        }
    }
Run Code Online (Sandbox Code Playgroud)

这是开始处理的方法:

        private void btnGo_Click(object sender, EventArgs e)
    {
        if (btnGo.Text == "Cancel")
        {
            if (DialogResult.Yes == MessageBox.Show("Are you sure you wish to cancel?", "Cancel Requested", MessageBoxButtons.YesNo, MessageBoxIcon.Question))
                bgw.CancelAsync();

            return;
        }

        if (tbFind.Text.Length == 0)
        {
            MessageBox.Show("Find text is not valid.");
            return;
        }

        tbFound.Text = String.Empty;
        tbFoundInThisFile.Text = String.Empty;
        lvResults.Items.Clear();
        includeList = null;
        excludeList = null;
        results = null;

        if (radDirectory.Checked && !radFile.Checked)
        {
            includeList = BuildIncludeExcludeList(tbIncludeFiles.Text);
            excludeList = BuildIncludeExcludeList(tbExcludeFiles.Text);
        }

        ProcessParameters pp = null;

        if (chkReplace.Checked)
            pp = new ProcessParameters(tbPath.Text, tbFind.Text, tbReplace.Text, chkUseRegEx.Checked, includeList, excludeList, chkRecursion.Checked, chkIgnoreCase.Checked, true);
        else
            pp = new ProcessParameters(tbPath.Text, tbFind.Text, chkUseRegEx.Checked, includeList, excludeList, chkRecursion.Checked, chkIgnoreCase.Checked, false);

        bgw.RunWorkerAsync(pp);

        // Toggle fields to locked while it's running
        btnGo.Text = "Cancel";
    }
Run Code Online (Sandbox Code Playgroud)

这是WorkerCompleted()事件:

        private void bgw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
    {
        btnGo.Text = "Go";

        string message = String.Empty;
        const string caption = "FindAndReplace is Complete";

        if (!e.Cancelled)
        {
            if (results != null)
            {
                tbFound.Text = results.Found.ToString();
                tbSearched.Text = results.FilesSearched.ToString();
                tbSkipped.Text = results.FilesSkipped.ToString();

                message = String.Format("Search finished resulting in {0} match(es).", results.Found);
            }
            else
                message = "The FindAndReplace results were empty. The process was cancelled or there was an error during operation.";
        }
        else
            message = "The FindAndReplace process was cancelled.";

        if (e.Error != null)
            message += String.Format("{0}{0}There was an error during processing: {1}", Environment.NewLine, e.Error);

        MessageBox.Show(message, caption);
    }
Run Code Online (Sandbox Code Playgroud)

zim*_*nen 7

CancelAsync实际上并没有中止你的线程或类似的东西.它向工作线程发送一条消息,通过BackgroundWorker.CancellationPending取消工作.您在后台运行的DoWork委托必须定期检查此属性并自行处理取消.

在这里阅读更多


sal*_*uce 5

你真的没有办法取消这个操作.问题是这段代码

               if (pp.DoReplace)
                    results = FindReplace.FindReplace.FindAndReplace(pp.PathToSearch, pp.FindText, pp.ReplaceText, pp.UseRegularExpressions, pp.IncludeList, pp.ExcludeList, pp.RecurseSubdirectories, pp.IgnoreCase);
                else
                    results = FindReplace.FindReplace.Find(pp.PathToSearch, pp.FindText, pp.UseRegularExpressions, pp.IncludeList, pp.ExcludeList, pp.RecurseSubdirectories, pp.IgnoreCase);
Run Code Online (Sandbox Code Playgroud)

一旦它开始运行就没有办法打破.所以,最后发生的事情是你点击取消,但取消永远不会注册,除非你在行动开始之前取消了.该操作完成后,DoWork方法成功返回,后台工作程序永远不会触发取消.

编辑:如果你有办法将文本分成较小的块然后可以"搜索和替换",你可以循环这些段并对每个循环执行取消检查.但是,您需要确保考虑跨越这些中断边界的搜索字符串,因此实际上可能需要LONGER来取消.

  • 由于你的DoWork方法基本上只运行一个命令,然后没有,实际上没有办法取消那个命令.您只能检查命令之间的取消(特别是在循环时).或许,你可以将文本分成更小的段,然后遍历`FindReplace`,检查每个循环的取消. (3认同)
  • 如果操作被取消,你可以修改WorkerCompleted什么都不做......或者如果工人成功完成,它甚至可以注册?我对中止线程持怀疑态度,但那可能就是我. (2认同)