Just giving another flavour of the solution for c# 4.0. This is similar to @Debora and @Jay (well, if you forget about the while(true)... just talking about the BeginInvoke) solutions, but fully based on TPL and the one that gets closer to the code generated with async/await:
TaskScheduler uiScheduler = TaskScheduler.FromCurrentSynchronizationContext();
Task.Factory.StartNew(() =>
{
for (int i = 0; i < 10; i++)
{
Task.Factory.StartNew(() =>
{
listBox1.Items.Add("Number cities in problem = " + i.ToString());
}, CancellationToken.None, TaskCreationOptions.None, uiScheduler);
System.Threading.Thread.Sleep(1000);
}
}, CancellationToken.None, TaskCreationOptions.None, TaskScheduler.Default);
Your work task should be scheduled using the default TaskScheduler (that will use the ThreadPool) and use the uiScheduler to callback to the UI thread when required to update the UI.
Keep in mind that this is a sample implementation and there could be some problems with this sample, for instance, the inner task is scheduled to execute on the UI thread, but it is not waited by the calling task, so the sleep will actually run while the inner task is running.
It is also very important that you do not wait for the tasks, or you could have a deadlock (inner task is trying to run on the UI thread that is blocked waiting for the outer task).
I usually use the uiScheduler on continuation task to provide the data to the UI. In your case it could be something like this:
TaskScheduler uiScheduler = TaskScheduler.FromCurrentSynchronizationContext();
Task.Factory.StartNew(() =>
{
//load data or perform work on background thread
var itemList = new List<int>();
for (int i = 0; i < 10; i++)
{
itemList.Add(i);
System.Threading.Thread.Sleep(1000);
}
return itemList;
}).ContinueWith((itemList) =>
{
//get the data from the previous task a continue the execution on the UI thread
foreach(var item in itemList)
{
listBox1.Items.Add("Number cities in problem = " + item.ToString());
}
}, CancellationToken.None, TaskCreationOptions.None, uiScheduler);
The resulting compiled code will be very similar (if not equal) to the code generated with async/await