Runar Ovesen Hjerpbakk

Science-based software development

From UIAlertView to UIAlertController using Xamarin and async / await

UIAlertView has been deprecated by Apple from iOS8. From now on, UIAlertController is the way to go. UIAlertController is surely an improvement, but given the asynchronous nature of displaying alerts to the user, I wanted to use the API together with async and await.

Below is a screenshot of what I wanted to accomplish:

Customer feedback sheet

A simple menu with two options and a Cancel-button.

UIAlertController lets you add multiple UIAlertActions, each with its own handler which is just a normal Action. I want to present the menu to the user and wait for her to select one of the items.

By using a TaskCompletionSource, I can accomplish this using async and await.

public static class CustomerFeelingSheet {
  public static Task<CustomerFeeling> ShowRatingDialogAsync(UIViewController parent) {
    var taskCompletionSource = new TaskCompletionSource<CustomerFeeling>();

    var alert = UIAlertController.Create(
      "howDoYouFeel".T(), null, UIAlertControllerStyle.ActionSheet);

    alert.AddAction(UIAlertAction.Create(
      "likeIt".T(), UIAlertActionStyle.Default,
      a => taskCompletionSource.SetResult(CustomerFeeling.LikeIt)));
    
    alert.AddAction(UIAlertAction.Create(
      "couldBeBetter".T(), UIAlertActionStyle.Default,
      a => taskCompletionSource.SetResult(CustomerFeeling.CouldBeBetter)));
    
    alert.AddAction(UIAlertAction.Create(
      "cancel".T(), UIAlertActionStyle.Cancel,
      a => taskCompletionSource.SetResult(CustomerFeeling.DontCare)));

    parent.PresentViewController(alert, true, null);
    return taskCompletionSource.Task;
  }
}

The TaskCompletionSource can be used to map an external asynchronous operation onto a normal C# Task. We can then use this task as we would any other.

In this case, the result of this task is the Enum CustomerFeeling with values corresponding to the users happiness. Thus, ShowRatingDialogAsync can be used like this:

var customerFeeling = await CustomerFeelingSheet.ShowRatingDialogAsync(parentVC);
switch(customerFeeling) {
  case CustomerFeeling.LikeIt:
    // "I like it!" was chosen 
    break;
  case CustomerFeeling.CouldBeBetter:
    // "It could be better..." was chosen
    break;
  default:
    // "Cancel" was chosen
    return;
}

The choice of the user can be awaited and UIAlertController now fits in perfectly with the rest of the C# code.