I want status updates from a long running method. Usually I'd use the dispatcher to post back to the UI thread, but I'm curious about using async await.
To keep it simple:
Create a window, add a button
<Button Name="ButtonWithCodeBehind" Height="25" Click="ButtonWithCodeBehindOnClick"/>
add some code behind onClick handler
private async void ButtonWithCodeBehindOnClick(object sender, RoutedEventArgs e)
{
await Task.Factory.StartNew(() =>
{
ButtonWithCodeBehind.Content = "First";
Thread.Sleep(1000);
ButtonWithCodeBehind.Content = "Second";
Thread.Sleep(1000);
ButtonWithCodeBehind.Content = "Third";
});
}
This will obviously break because ButtonWithCodeBehind.Content will be accessed on the wrong thread.
Is there a way to make this work without doing something like:
Deployment.Current.Dispatcher.BeginInvoke(()=>ButtonWithCodeBehind.Content = "Second");
The critical thing here is the long running task will be generating updates as it progresses, I can refactor the code to something like this:
private async void ButtonWithCodeBehindOnClick(object sender, RoutedEventArgs e)
{
var scheduler = TaskScheduler.FromCurrentSynchronizationContext();
await Task.Factory.StartNew(() =>
{
Task.Factory.StartNew(() => Thread.Sleep(1000))
.ContinueWith(t => ButtonWithCodeBehind.Content = "First", scheduler)
.ContinueWith(t => Thread.Sleep(1000))
.ContinueWith(t => ButtonWithCodeBehind.Content = "Second", scheduler)
.ContinueWith(t => Thread.Sleep(1000))
.ContinueWith(t => ButtonWithCodeBehind.Content = "Third", scheduler);
});
}
But this is fugly. Also, if you took out the async and await keywords and replaced them with Task.WaitAll, it would still execute as expected.
Note: If you're wondering why I'm using Thread.Sleep instead of Task.Delay, I'm actually testing this in Silverlight as well and the async await support doesn't include .Delay (or at least not where I expect it to be).