Paul Michaels
Paul Michaels

Reputation: 16685

Awaiting a task not behaving the way I would expect

I have a code path which is not behaving the way I would expect; I possibly have a bug, but I suspect it's more likely that there is something about awaiting a task that I misunderstand. The aim of the following code is to navigate to a second screen and then, based on a timeout, navigate back again and try to share some content:

AdvertHelper adHelper = new AdvertHelper();

Task nav = new Task(async () =>
{
    await CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, async () =>
    {
        System.Diagnostics.Debug.WriteLine("Call Navigate to MainPageViewModel");
        Navigation.Navigate<MainPageViewModel>();

        saved = await SaveVideo();
        System.Diagnostics.Debug.WriteLine("After SaveVideo()");
    });
});
adHelper.DisplayAdvert(this, nav);

System.Diagnostics.Debug.WriteLine($"Before await nav (saved: {saved})");
await nav;
System.Diagnostics.Debug.WriteLine($"After await nav (saved: {saved})");

DisplayAdvert looks like this:

    public void DisplayAdvert(BaseViewModel sourceVM, Task afterAdvert)
    {                        
        _afterShow = afterAdvert;
        _tmr = new DispatcherTimer();
        _tmr.Tick += _tmr_Tick;
        _tmr.Interval = new TimeSpan(0, 0, 2);
        _tmr.Start();

        Navigation.Navigate<AdvertViewModel>();
    }

and the timeout:

    private void _tmr_Tick(object sender, object e)
    {            
        _afterShow.Start();
        _tmr.Stop();
    }

So, my understanding is that I have created a task that will navigate to the MainPageViewModel, then attempt to save the video (for the purpose of this, imagine the SaveVideo() simply returns true in an async function after a period of several seconds.

From the debugging:

Before await nav (saved: False)
Call Navigate to MainPageViewModel
SaveVideo() Called
After await nav (saved: False)
SaveVideo() Return true
After SaveVideo()

So, if I'm reading this correctly, the code is not awaiting the task nav (and therefore SaveVide()), but is continuing and therefore not getting the result of SaveVideo() at the correct time.

Upvotes: 2

Views: 71

Answers (1)

Stephen Cleary
Stephen Cleary

Reputation: 456322

The core problem you're seeing is that the Task constructor does not understand async delegates. You should never, ever use the Task constructor; as I describe on my blog, there are no use cases for it. Ever.

The aim of the following code is to navigate to a second screen and then, based on a timeout, navigate back again and try to share some content

Then why not something like this?

Navigation.Navigate<AdvertViewModel>();
await Task.Delay(2);
Navigation.Navigate<MainPageViewModel>();
saved = await SaveVideo();

Upvotes: 4

Related Questions