如何在C#中使一个类中的长时间运行的方法向调用它的类报告其进度?

3

我有一个处理成千上万项目的方法,需要很长时间。

如何正确地让执行长时间操作的方法在执行时报告其进度?

例如,如果我想在我的用户界面中显示另一个线程中某个长时间运行的方法的进度条。

3个回答

4

这样只更新UI不是有点浪费吗?将长时间运行的进程分割并进行线程处理,而不仅仅是从一个长时间运行的进程中报告,这难道不是更好的解决方案吗? - Tim Jarvis

1
在这种情况下,我倾向于创建一个自定义事件,并从长时间运行的进程中触发它,然后在事件处理程序中订阅任何您想要更新的UI元素。(UI总是在主UI线程中更新)

自定义事件的缺点是它们需要被编组到订阅者的线程中,这涉及编写一些额外的代码。但是BackgroundWorker可以完美地处理这个问题。 - Aviad P.
我认为仅仅在一个锁定的用户界面上放置一个进度条并不能让用户感到满意,因此我认为可以安全地假设OP也想要一个单独的线程。 - ProfK
@Aviad,@ProfK,你们听说过KISS吗?BackgroundWorker并不是所有关于长时间运行代码的问题的答案。很高兴看到其他人(比如Tim)也意识到有替代方案。 - Ash
“UI总是在主线程中更新” - 这不是自动的。您需要使用Control.Invoke来更新从后台线程触发的事件处理程序中的UI元素。或者使用BackgroundWorker,它会为您处理这个问题。 - Joe

1

长时间运行的任务可能想以两种方式之一与调用者通信,无论是在专用后台线程中运行还是不在其中:

  • 报告进度(使用BackgroundWorker时对应于调用 BackgroundWorker.ReportProgress

  • 检查是否已请求取消(使用BackgroundWorker时对应于检查CancellationPending 属性)。

长时间运行的进程有时候有必要能够以这种方式与调用者通信,而不知道或不关心它是否从BackgroundWorker中运行。 因此,我创建了一个接口IProgress,通过方法ReportProgress和属性CancellationPending抽象出这个功能。 我有一个增强版的BackgroundWorker实现了这个接口,并且还有其他不使用BackgroundWorker的替代实现。

例如,控制台应用程序可能在前台运行长时间任务。如果在详细模式下运行,则其实现IProgress.ReportProgress可以使用Console.WriteLine。其实现IProgress.CancellationPending可以检查是否按下CTRL-C。相同的长时间运行任务可以从此控制台应用程序和使用BackgroundWorker的WinForms应用程序中调用。
个人认为,在设计BackgroundWorker时,应该将这样的抽象包含在.NET Framework中。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接