[WPDev] CustomMessageBox + OnNavigatedTo + Navigate = Exception !

, , Comments Off on [WPDev] CustomMessageBox + OnNavigatedTo + Navigate = Exception !

CustomMessageBoxThe Windows Phone Toolkit is really useful.

Yesterday, while I was updating my ConsoTracker app, I met a strange bug using the CustomMessageBox : it was raising a nullReference exception.

Let’s see what was the issue and how to “fix” it.

What I was trying to do was this simple scenario :

  1. Ask the use if he wants to review my app in the OnNavigatedTo event using a CustomMessageBox
  2. If he answers ‘no’, navigate to another page.
  3. If it answers ‘yes’, show the marketplace review task.

As I like playing with tasks, I was using this code :
[csharp]
protected async override void OnNavigatedTo(NavigationEventArgs e)
{
base.OnNavigatedTo(e);
var mBox = new CustomMessageBox
{
Title = "Do you want to… ",
Message = " … click on yes ?",
LeftButtonContent = "Yes",
RightButtonContent = "No"
};
var result = await ShowAsync(mBox);
NavigationService.Navigate(new Uri("/OtherPage.xaml", UriKind.RelativeOrAbsolute));
}

public static async Task<CustomMessageBoxResult> ShowAsync(CustomMessageBox box)
{
var taskCompletionSource = new TaskCompletionSource<CustomMessageBoxResult>();
box.Dismissed += (a, b) => taskCompletionSource.TrySetResult(b.Result);

try { box.Show(); }
catch (Exception exception) { taskCompletionSource.TrySetException(exception); }

return await taskCompletionSource.Task;
}
[/csharp]

This code was throwing an exception. To fix it, I downloaded the source of the Windows Phone Toolkit and I saw that at the end of the dismissal animation, it was trying to access the “Popup” object which was null : BOUM !

So… how did I fix it ? Simply by waiting for the popup to be unloaded instead of using directly the Dismissed event of the CustomMessageBox :
[csharp]
public static async Task<CustomMessageBoxResult> ShowAsync(CustomMessageBox box)
{
var taskCompletionSource = new TaskCompletionSource<CustomMessageBoxResult>();
var result = CustomMessageBoxResult.None;

//Only store the result here.
box.Dismissed += (a, b) => result = b.Result;

//Use this event to set the result.
box.Unloaded += (_, __) => taskCompletionSource.TrySetResult(result);

try { box.Show(); }
catch (Exception exception) { taskCompletionSource.TrySetException(exception); }

return await taskCompletionSource.Task;
}
[/csharp]

I hope it will save you some time too 🙂