One of the challenges often faced by developers is that they have code that needs to run at startup. This code typically has to run before any page begins to load its content; it has to support deep – linking, so shouldn’t be page dependent; and should never block the UI (which if done for long enough would cause the app to crash). In this post I’ll show you one way to achieve this – I’m sure there are plenty of other options.
In the constructor for the application make a call to your initialization method. This initialization method will return almost instantaneously since it simply spawns another thread.
public App()
{
// Standard init code for a Windows Phone app …
// This can be called here since all it does is pass off to another thread for the long running tasks to run.
// If this code requires the app to be further in the lifecycle, then you may need to
// move to launching/activating event handlers
InitCodeThatTakeAWhile();
}
And now for the initialization method. As mentioned, the first thing it does is to spawn another thread using Task.Run. Despite warnings from Resharper we do not await this call, since this would prevent the app from initializing correctly. Inside the Run we can do whatever we want to initialize the application. When it’s done, it simply calls Set on the ManualResetEvent.
private static readonly ManualResetEvent initWaiter = new ManualResetEvent(false);
private async void InitCodeThatTakeAWhile()
{
// DON’T wait, or you’ll block the caller
Task.Run(async () =>
{
// Put init code here – can take as long as you want
await Task.Delay(10000);
initWaiter.Set();
});
}
The App class also exposes a method which is used to wait for the ManualResetEvent to be set. It does this on a separate thread, thus allowing any UI code to continue to execute.
public static async Task WaitForInitToFinish()
{
// Switch to a different thread to wait, thereby allowing UI to process
await Task.Run(() =>
{
initWaiter.WaitOne();
});
}
Lastly, we need to invoke the wait method. This should be done on any page which is, or could be, used as a startup or launch page for the application. In fact, you could create a base class and call the WaitForInitToFinish method by overriding the OnNavigtedTo method.
protected async override void OnNavigatedTo(NavigationEventArgs e)
{
base.OnNavigatedTo(e);
// Change to loading states….
LoadingText.Text = "Loading….";
// Wait for init to complete
await App.WaitForInitToFinish();
// Now do page init code
LoadingText.Text = "Loaded";
}
This strategy is useful for triggering startup logic, whilst ensuring the UI doesn’t block