Just created a WPF project .net 4.6
And have put this code inside
lbl1
is a label on the GUI
But the label is never updated or the while loop continue only 1 time
private void Button_Click_1(object sender, RoutedEventArgs e)
{
var t = Task.Run(
async () =>
{
await AsyncLoop();
});
}
async Task AsyncLoop()
{
while (true)
{
string result = await LoadNextItem();
lbl1.Content = result;
}
}
private static int ir11 = 0;
async Task<string> LoadNextItem()
{
ir11++;
return "aa " + ir11;
}
Please user Application.Current.Dispatcher.Invoke to access the ui thread
The C# compiler is giving you a warning that tells you what the problem is.
Specifically, this method is not asynchronous:
The compiler message will inform you that this
async
method has noawait
statements, and thus will run synchronously. You should only useasync
where it makes sense, usually for I/O-based operations, e.g.:Alternatively, if you don't have asynchronous operations, but rather you have some tight CPU-bound loops, then you can push those off to a background thread via
Task.Run
:By invoking Task.Run you broke your association(SynchronizationContext) with the GUI thread (or WPF Dispatcher) and lost most of the async/await 'goodness'.
Why not use an async void event handler and just come back to the SynchronizationContext(GUI Thread/Dispatcher) for each step?
Or if you really want to separate the state machine for the 'on-going' operations, try passing an
IProgress<T>
(the default impl.Progress<T>
or specificallyProgress<string>
should work great in this case). See this article by @Stephen ClearyHis example is very close to what you stated in the question. I've copied it here for SO independence.
Edit: I must admit, while
Progress<T>
is a nice abstraction, in this case it is just going to fall down to Dispatcher.Invoke as @Pamparanpa suggested.