I have a really simple operation on a WPF app in order to try out async operations. Here is my complete code:
static int GetPrimes() {
var query =
from n in Enumerable.Range(3, 5000000).AsParallel()
where Enumerable.Range(2, (int)Math.Sqrt(n)).All(i => n % i > 0)
select n;
return query.Count();
}
private void button1_Click(object sender, RoutedEventArgs e) {
Task<int> task = Task.Factory.StartNew(
() => GetPrimes(),
TaskCreationOptions.LongRunning
);
task.ContinueWith(x => {
label1.Content = task.Result;
});
}
As you see, when I push the button it does some stuff and when it finishes it needs to push the result to a label but it doesn't do that.
I tested this synchronously and it worked.
What am I missing here?
You don't explain what "it doesn't do that" means. I assume you're getting an exception because you're trying to manipulate a UI element from the wrong thread?
The problem is this code:
task.ContinueWith(x => {
label1.Content = task.Result;
});
You're not specifying which thread you want your continuation to run on, so it could be running on any thread. It's probably going to run on the same thread as your first task, i.e., a thread pool thread. Since you're not allowed to access UI from a thread other than the thread it was created on, that means your label1.Content
assignment will fail with an exception.
The fix is simple: run your continuation on the UI thread. Change the above code to this:
task.ContinueWith(x => {
label1.Content = task.Result;
}, TaskScheduler.FromCurrentSynchronizationContext());
Since you're working with background threads, you will need to marshal any code that plays with the UI to the UI thread.
task.ContinueWith(x => {
Dispatcher.Invoke(() =>
{
label1.Content = task.Result;
},
null);
});