【问题标题】:Canceling Backgroundworker that was set using a lambda取消使用 lambda 设置的 Backgroundworker
【发布时间】:2013-03-24 00:52:49
【问题描述】:

我有一个使用 lambda 创建的后台工作程序,如下所示:

BackgroundWorker fileCountWorker= new BackgroundWorker();
fileCountWorker.WorkerSupportsCancellation = true;
fileCountWorker.DoWork += new DoWorkEventHandler((obj, e) => GetFileInfo(folder, subs));
fileCountWorker.RunWorkerCompleted += new RunWorkerCompletedEventHandler((obj, e) => UpdateCountInFolderListViewForItem(index));
fileCountWorker.RunWorkerAsync(); 

我希望能够取消后台工作程序,然后知道它是在 RunWorkerCompleted 函数中使用 RunWorkerCompletedEventArgs e.Canceled 属性取消的。

到目前为止,我一直无法找到将参数传递给 RunWorkerCompleted 函数并仍然保持访问 RunWorkerCompletedEventArgs 的能力的方法。

我尝试在 RunWorkerCompleted 调用的函数中添加一个 RunWorkerCompletedEventArgs 参数,然后像这样传递 RunWorkerCompletedEventArgs:

fileCountWorker.RunWorkerCompleted += new RunWorkerCompletedEventHandler((obj, e) => UpdateCountInFolderListViewForItem(index, e));

但这似乎不起作用。

有没有办法做到这一点?

编辑

按照下面的cmets,我做了以下更改:

我将DoWork Event更改如下(在worker函数中添加obj和e作为参数):

fileCountWorker.DoWork += new DoWorkEventHandler((obj, e) => GetFileInfo(folder, subs,obj,e));

然后我将 RunWorkerCompleted 函数更改如下(在 RunWorkerCompleted 函数中添加 obj 和 e 作为参数):

fileCountWorker.RunWorkerCompleted += new RunWorkerCompletedEventHandler((obj, e) => UpdateCountInFolderListViewForItem(index, obj, e));

我从我的 UI 线程调用 CancelAsync:

if (bgw.WorkerSupportsCancellation)
   {
      bgw.CancelAsync();
   }

然后,我从后台工作人员中检查取消挂起,例如:

BackgroundWorker bwAsync = sender as BackgroundWorker;
if (bwAsync.CancellationPending)
   {
      e.Cancel = true;
      return;
   }

结果是,当我取消backgroundworker时,它确实停止了worker函数,但是RunWorkerCompleted函数(UpdateCountInFolderListViewForItem)中的RunWorkerCompletedEventArgs仍然有一个Canceled属性设置为False,所以函数无法判断worker被取消了.

所以我仍然坚持让 RunWorkerCompleted 函数知道工人被取消而不是正常完成。

【问题讨论】:

  • 将 backgroundworker 与 lambdas 一起使用是一个非常糟糕的主意。使用 Task (TPL) 或 async/await 或至少 BeginInvoke。
  • @Andrey Care 详细说明为什么 lambdas 是一个非常糟糕的主意?
  • @PeterRitchie 因为 lambda 是一个小的工作单元,并且有更合适的工具来运行这些东西。
  • @Andrey 一个语句 lambda 可以有很多行(只要你想多行,假设你的 .cs 文件没有超过编译器可以接受的长度。lambda 只是一个匿名方法。 ..
  • @Andrey 感谢 Andrey,我不知道 Task(TPL),但是按照你的提示,我在 codeproject 上找到了一篇解释它的文章,我现在正在研究它。

标签: c# lambda backgroundworker


【解决方案1】:

您只需拨打BackgroundWorker.CancelAsync()

您的工作人员代码需要检查BackgroundWorker.CancellationPending 并停止它正在执行的“取消”操作...但是,您的 lambda 并没有做任何您可以真正取消的操作。

通常你会做这样的事情:

//...
fileCountWorker.DoWork += (obj, e) =>
{
    for (int i = 0; i < 1000 && fileCountWorker.CancellationPending; ++i)
    {
        Thread.Sleep(500);/* really do other work here */
    }
    e.Cancel = fileCountWorker.CancellationPending;
};

fileCountWorker.RunWorkerAsync(); 

//...

fileCountWorker.CancelAsync();

如果您提供GetFileInfo 的一些详细信息,也许可以提供更多详细信息。

【讨论】:

  • 这只是为什么 BackgroundWorker+lamdas 不能很好地发挥作用。
  • @Andrey 再次,以什么方式?
  • @PeterRitchie 问题是当我调用 fileCountWorker.CancelAnsync();它确实取消了工作程序,然后调用了 RunWorkerCompleted 函数,但是,我无法在 RunWorkerCompleted 函数中判断后台工作程序是自行完成还是被取消(我将使用 RunWorkerCompletedEventArgs 进行测试。GetFileInfo 只是一个函数即使用 DirectoryInfo 进行 EnumerateFiles()。所以如果 RunWorkerCompleted 函数也是使用 lambda 创建的,你还能从 worker 中获取 RunWorkerCompletedEventArgs 吗?
  • @Blau RunWorkerCompleted 将始终被调用,即使您取消(请参阅RunWorkerCompletedEventArgs.Cancelled。但要取消,您的代码需要检查 CancellationPendingCancelAsync 不会神奇地停止您的代码无法运行——您的代码必须明确取消。RE 事件参数:当然,您的 Lamba 中的 eRunWorkerCompletedEventArgs 对象
  • @PeterRitchie 根据您的建议,我进行了一些更改并将其作为编辑发布在原始帖子中。我还没弄明白。
猜你喜欢
  • 2015-01-21
  • 1970-01-01
  • 2018-03-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多