public static async Task <TResult> ShowModal <TViewController, TResult>( UIViewController parentViewController, TViewController viewController, Action <TViewController, Action> dismissSubscriber = null, UIModalPresentationStyle presentationStyle = UIModalPresentationStyle.FormSheet, UIModalTransitionStyle transitionStyle = UIModalTransitionStyle.CoverVertical, Action completionHandler = null, Func <TViewController, TResult> resultGetter = null, bool dismissOnTapOutside = true, bool disposeOnFinish = false ) where TViewController : UIViewController { try { if (completionHandler == null) { completionHandler = Tools.Lambda.NoOp; } if (dismissOnTapOutside && presentationStyle.IsIn(UIModalPresentationStyle.FullScreen, UIModalPresentationStyle.OverFullScreen)) { dismissOnTapOutside = false; } if (dismissSubscriber == null && dismissOnTapOutside == false) { throw new ArgumentException("dismissSubscriber is null and dismissOnTapOutside is effectively false, this will result in an unclosable modal screen"); } var signal = new ManualResetEventSlim(); viewController.ModalPresentationStyle = presentationStyle; viewController.ModalTransitionStyle = transitionStyle; Action dismissModalDialogAction = signal.Set; dismissSubscriber(viewController, dismissModalDialogAction); var currentPresentedController = parentViewController.FindPresentedViewController(); if (currentPresentedController != null) { parentViewController = currentPresentedController; } viewController.ProvidesPresentationContextTransitionStyle = true; viewController.DefinesPresentationContext = true; await parentViewController.PresentViewControllerAsync(viewController, true); completionHandler(); var window = parentViewController.View.Window; UITapGestureRecognizerEx tapOutsideGesture = null; if (dismissOnTapOutside) { tapOutsideGesture = new UITapGestureRecognizerEx(async(x) => { if (x.State == UIGestureRecognizerState.Ended) { var location = x.LocationInView(null);//Passing nil gives us coordinates in the window if (!viewController.View.PointInside(viewController.View.ConvertPointFromView(location, window), null)) { //Convert tap location into the local view's coordinate system. If outside, dismiss the view. signal.Set(); } } }); tapOutsideGesture.NumberOfTapsRequired = 1; tapOutsideGesture.CancelsTouchesInView = false; window.AddGestureRecognizer(tapOutsideGesture); } await Task.Run(() => signal.Wait()); if (dismissOnTapOutside) { window.RemoveGestureRecognizer(tapOutsideGesture); } if (!viewController.IsBeingDismissed && parentViewController.ModalViewController == viewController) { await viewController.DismissViewControllerAsync(true); } return(resultGetter == null ? default(TResult) : resultGetter(viewController)); } finally { if (disposeOnFinish) { viewController.Dispose(); } } }