Reputation: 1278
I'm using TPL in a Windows Form Application in the following way:
foreach (var item in items)
{
task = Task<object>.Factory.StartNew (() => doWork());
task.Wait();
//update the UI using the result
}
I am waiting for the task to finish, because I need to process every item in the list, but as you imagine this is causing a lock in my UI thread (the UI freezes).
I'd like to know how can I implement this in a way that does not lock the UI thread.
Update: I'm using .NET Framework 4.5
Thanks.
P.S DoWork() is a long run operation.
Upvotes: 1
Views: 4946
Reputation: 54887
Make your event handler async
, and call await
on the task representing the thread pool operation. This will cause your event handler to relinquish control over the UI thread until the task completes, then resume to update the UI and start the next task.
private async void MyButton_Click(object sender, EventArgs e)
{
foreach (var item in items)
{
// assuming C# 5 closure semantics
await Task.Run(() => doWork(item));
// update the UI using the result
}
}
The above approach assumes that you want to run your tasks sequentially. If you want to launch them in parallel and process their results in order of completion, you could use:
private async void MyButton_Click(object sender, EventArgs e)
{
var tasks = items.Select(item => Task.Run(() => doWork(item))).ToList();
while (tasks.Any())
{
var task = await Task.WhenAny(tasks);
tasks.Remove(task);
var result = await task;
// update the UI using the result
}
}
Upvotes: 2
Reputation: 149538
You can go about this in a couple of ways.
One would be not to execute each item in your list on a thread pool thread, but queue the entire foreach loop inside a Task
and then update the results when they finish.
public async void SoneEventHandler(object sender, EventArgs e)
{
var result = await Task.Run(() => items.Select(item => DoWork()).ToList());
foreach (var item in items)
{
// Update UI
}
}
If you still want to process each item on a threadpool threas, use Task.Run
and await
on the Task
, don't block with Task.Wait()
:
public async void SoneEventHandler(object sender, EventArgs e)
{
foreach (var item in items)
{
var result = await Task.Run(() => DoWork());
// Update UI
}
}
Upvotes: 3