Search code examples
c#while-loopwindows-phonefreezethread-sleep

Windows Phone: Task.Delay not working / Application hanging on a page


I am producing an application for Windows Phone 8.1. When a user navigates to a certain Page of the app, a block of code in the OnNavigatedTo() method is called. Here is what it looks like:

protected override void OnNavigatedTo(NavigationEventArgs e)
{
    while (!hasUserWonGame)
    {
        Task.Delay(3000);
        //do stuff...
        Task.Delay(6000);
        //do more stuff...
        Task.Delay(2000);
        //do more stuff...
    }
}

While debugging, once I clicked the button to navigate to this page, the application simply hanged at that page without even navigating to the page. Commenting the while block out, the application works fine. It also works fine if you add any statement outside the block. However, commenting in the smallest part of the loop, even with Task.Delay, gets me stuck (essentially) in a while (true) loop.

The problem is, the user can't even navigate to the page, so there's no way to change hasUserWonGame to true. Why is Task.Delay() not working, and letting the application continue navigating to the page?


Solution

  • Without a good, minimal, complete code example, it's impossible to know for sure what you really want here. But for sure, you seem to misunderstand what Task.Delay() does, and maybe we can guess at a way to fix your code in spite of the lack of detail.

    The Task.Delay() method, like any asynchronous method, does not actually perform the work and wait to return until it's done. Instead, by calling it you are telling the method you want the delay to happen, and the method responds by returning you a Task instance which you can use to determine when that work (i.e. the delay) is actually done.

    The normal way to take advantage of this is to use the await statement, and to use that you have to have an async method. Which is actually good, because if we make your OnNavigatedTo() method an async method, then it can return right away and let your program get on with the things it needs to do, rather than locking up your user interface.

    So, for example, we might change the method to look more like this:

    protected async override void OnNavigatedTo(NavigationEventArgs e)
    {
        while (!hasUserWonGame)
        {
            await Task.Delay(3000);
            //do stuff...
            await Task.Delay(6000);
            //do more stuff...
            await Task.Delay(2000);
            //do more stuff...
        }
    }
    

    Now, it's very important: in any of the "stuff" that method also does, you need to make sure it's all "stuff" that can be done quickly. You don't want to make that method take any significant amount of time to do anything; just normal UI-related operations and a small amount of computations.

    If the method does need to do anything that is time-consuming enough that the user would notice the UI getting frozen while that code runs, you need to (preferably) separate that code out into a different method, and then call that method from a Task instance, awaiting the Task. For example, something like await Task.Run(() => MyLengthyOperation());.