diff --git a/src/Uno.UWP/UI/Popups/MessageDialog.Android.cs b/src/Uno.UWP/UI/Popups/MessageDialog.Android.cs index d74723785ab4..e1e1040be8cc 100644 --- a/src/Uno.UWP/UI/Popups/MessageDialog.Android.cs +++ b/src/Uno.UWP/UI/Popups/MessageDialog.Android.cs @@ -13,6 +13,7 @@ using Android.Widget; using Windows.UI.Core; using Windows.Foundation; +using System.Threading; namespace Windows.UI.Popups { @@ -20,10 +21,8 @@ public partial class MessageDialog { const int MaximumCommands = 3; - public IAsyncOperation ShowAsync() + private void ShowInner(CancellationToken ct, TaskCompletionSource invokedCommand) { - var invokedCommand = new TaskCompletionSource(); - // Android recommends placing buttons in this order: // 1) positive (default accept) // 2) negative (default cancel) @@ -35,7 +34,7 @@ public IAsyncOperation ShowAsync() .Where(command => !(command is UICommandSeparator)) // Not supported on Android .DefaultIfEmpty(new UICommand("Close")) // TODO: Localize (PBI 28711) .Reverse() - .Select((command, index) => + .Select((command, index) => new { Command = command, @@ -62,20 +61,15 @@ public IAsyncOperation ShowAsync() } ); - return new AsyncOperation(async ct => + using (ct.Register(() => { - using (ct.Register(() => - { - // If the cancellation token itself gets cancelled, we cancel as well. - invokedCommand.TrySetCanceled(); - dialog.Dismiss(); - })) - { - dialog.Show(); - - return await invokedCommand.Task; - } - }); + // If the cancellation token itself gets cancelled, we cancel as well. + invokedCommand.TrySetCanceled(); + dialog.Dismiss(); + })) + { + dialog.Show(); + } } partial void ValidateCommands() diff --git a/src/Uno.UWP/UI/Popups/MessageDialog.cs b/src/Uno.UWP/UI/Popups/MessageDialog.cs index 03cf7c023360..bc6146b88692 100644 --- a/src/Uno.UWP/UI/Popups/MessageDialog.cs +++ b/src/Uno.UWP/UI/Popups/MessageDialog.cs @@ -5,6 +5,8 @@ using System.Text; using System.Threading; using System.Threading.Tasks; +using Windows.Foundation; +using Windows.UI.Core; namespace Windows.UI.Popups { @@ -14,7 +16,7 @@ public sealed partial class MessageDialog /// Creates a new instance of the MessageDialog class, using the specified message content and no title. /// /// - public MessageDialog(string content) + public MessageDialog(string content) : this(content, "") { } @@ -46,6 +48,53 @@ public MessageDialog(string content, string title) Commands = collection; } +#if __ANDROID__ || __IOS__ + + public IAsyncOperation ShowAsync() + { + var invokedCommand = new TaskCompletionSource(); + + return new AsyncOperation(async ct => + { + if (CoreDispatcher.Main.HasThreadAccess) + { + try + { + ShowInner(ct, invokedCommand); + } + catch (Exception e) + { + invokedCommand.TrySetException(e); + } + } + + else + { + Exception ex = null; + await CoreDispatcher.Main.RunAsync(CoreDispatcherPriority.Normal, CallShow); + + if (ex != null) + { + invokedCommand.TrySetException(ex); + } + + void CallShow() + { + try + { + ShowInner(ct, invokedCommand); + } + catch (Exception e) + { + ex = e; + } + } + } + return await invokedCommand.Task; + }); + } +#endif + public uint CancelCommandIndex { get; set; } = uint.MaxValue; public IList Commands { get; } public string Content { get; set; } diff --git a/src/Uno.UWP/UI/Popups/MessageDialog.iOS.cs b/src/Uno.UWP/UI/Popups/MessageDialog.iOS.cs index 73f4c4529ac0..b0a7b3f74ec3 100644 --- a/src/Uno.UWP/UI/Popups/MessageDialog.iOS.cs +++ b/src/Uno.UWP/UI/Popups/MessageDialog.iOS.cs @@ -16,10 +16,8 @@ public partial class MessageDialog { private static readonly SemaphoreSlim _viewControllerAccess = new SemaphoreSlim(1, 1); - public IAsyncOperation ShowAsync() + private async void ShowInner(CancellationToken ct, TaskCompletionSource invokedCommand) { - var invokedCommand = new TaskCompletionSource(); - var alertActions = Commands .Where(command => !(command is UICommandSeparator)) // Not supported on iOS .DefaultIfEmpty(new UICommand("OK")) // TODO: Localize (PBI 28711) @@ -51,36 +49,31 @@ public IAsyncOperation ShowAsync() alertController.PreferredAction = alertActions.ElementAtOrDefault((int)DefaultCommandIndex); } - return new AsyncOperation(async ct => - { - using (ct.Register(() => - { - // If the cancellation token itself gets cancelled, we cancel as well. - invokedCommand.TrySetCanceled(); - UIApplication.SharedApplication.KeyWindow?.RootViewController?.DismissViewController(false, () => { }); - })) + using (ct.Register(() => { - await _viewControllerAccess.WaitAsync(ct); + // If the cancellation token itself gets cancelled, we cancel as well. + invokedCommand.TrySetCanceled(); + UIApplication.SharedApplication.KeyWindow?.RootViewController?.DismissViewController(false, () => { }); + })) + { + await _viewControllerAccess.WaitAsync(ct); + try + { try { - try - { - await UIApplication.SharedApplication.KeyWindow?.RootViewController?.PresentViewControllerAsync(alertController, animated: true); - } - catch (Exception error) - { - invokedCommand.TrySetException(error); - } - - return await invokedCommand.Task; + await UIApplication.SharedApplication.KeyWindow?.RootViewController?.PresentViewControllerAsync(alertController, animated: true); } - finally + catch (Exception error) { - _viewControllerAccess.Release(); + invokedCommand.TrySetException(error); } } - }); + finally + { + _viewControllerAccess.Release(); + } + } } partial void ValidateCommands()