Backgroundworker.CancelAsync() 不起作用
本文关键字:不起作用 CancelAsync Backgroundworker | 更新日期: 2023-09-27 18:33:28
我有一个运行单个进程的后台工作者。我希望能够在处理过程中取消处理,但是当我调用 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;
}
}
}
以下是开始处理的方法:
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";
}
下面是 WorkerComplete() 事件:
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);
}
CancelAsync
实际上不会中止您的线程或类似的东西 那。它向工作线程发送一条消息,指出工作应该是 通过后台工作者取消。你的做工 在后台运行的委托必须定期检查 这家酒店并自行处理取消。
在此处阅读更多内容
您实际上没有办法取消该操作。 问题是这段代码
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);
一旦开始运行,就没有任何方法可以中断。 因此,最终发生的是你点击了取消,但取消永远不会注册,除非您在操作开始之前取消了。 该操作完成后,DoWork 方法将成功返回,并且后台工作线程永远不会触发取消。
编辑:如果您有办法将文本分解为较小的块,然后可以"搜索和替换",则可以循环访问这些片段并在每个循环中执行取消检查。 但是,您需要确保考虑搜索字符串跨越这些中断边界,因此实际上可能需要更长的时间才能允许取消。
你的代码是正确的,但如果你再仔细阅读一遍,你会发现一旦后台工作线程启动,它很快就会超越取消检查。之后,即使您尝试取消,它也将不再起作用。
您必须重新设计搜索和替换算法以包括取消检查,以便根据需要支持取消。