Question: I have a method that processes thousands of items and it takes a long time.

What is the "right" way to have the method that is doing the long operation report back its progress as it does this?

For example, if I wanted to have a progress bar in my UI show the progress of some long running method in another thread.

Answer: 
Use a [BackgroundWorker](http://msdn.microsoft.com/en-us/library/system.componentmodel.backgroundworker.aspx).

There are several SO questions on the BackgroundWorker, for example:

* [Background worker class and passing messages using progress events from a different class in c#](https://stackoverflow.com/questions/1675124/background-worker-class-and-passing-messages-using-progress-events-from-a-differe)
A long-running task, whether running in a dedicated background thread or not, may want to communicate with the caller in one of two ways:

* To report progress (with a BackgroundWorker this corresponds to calling `BackgroundWorker.ReportProgress`)
* To check if cancellation has been requested (with a BackgroundWorker this corresponds to examining the `CancellationPending` property).

It's sometimes useful for a long-running process to be able to communicate with the caller in this way without knowing or caring if it is being run from a BackgroundWorker. I have therefore created an interface `IProgress` which abstracts this functionality with a method `ReportProgress` and a property `CancellationPending`. I have an enhanced version of BackgroundWorker that implements this interface, and also alternative implementations that do not use a BackgroundWorker. 

For example, a console application might run a long-running task in the foreground. Its implementation of `IProgress.ReportProgress` could e.g. use `Console.WriteLine` if running in verbose mode. Its implementation of `IProgress.CancellationPending` could check if CTRL-C has been pressed. The same long-running task could be called from this console application and from a WinForms application that uses a BackgroundWorker.

Personally I think an abstraction like this should have been included in the .NET Framework when BackgroundWorker was designed.