Create a popup using Rg.Plugins.Popup and get a return value in Xamarin Forms

Hi my friends, how are you? I hope you are well.

In the last few weeks I have had a request from a client of mine to change the standard Xamarin Forms popups created with https://docs.microsoft.com/it-it/xamarin/xamarin-forms/user-interface/pop-ups, because his drivers have big fingers and cannot press the small “YES” and “NO”.

The only solution I have used during these years is https://github.com/rotorgames/Rg.Plugins.Popup, the “official” plugin to create customizable popup in Xamarin Forms. https://twitter.com/rotorgames_LK but not it seems that it appears to be maintained by the mythical https://twitter.com/mhvdijk.

We will have a new popup in Xamarin Community Toolkit but it is a work in progress: https://github.com/xamarin/XamarinCommunityToolkit/pull/653

Rg.Plugins.Popup works very well: you can create your popup as if it were a Xamarin Forms ContentPage. The only “problem” is that it seems there is no way to wait for its closure and have some kind of return data (or at least, I haven’t found how to do it).

So, thanks to Google, I’ve been looking for a way to replace all Xamarin Forms popups with a “custom” popup created with Rg.Plugins.Popup, but with the ability to wait for a return value without using MessagingCenter or other ways. I found a modality and would like to share it with you, also thanks to this example project that you can find on Github https://github.com/acaliaro/XamFormsAwaitablePopup.

This little demo shows 2 kind of popups:

  • The Xamarin Forms popup
  • A Rg.Plugins.Popup “classic”, not awaitable
  • A Rg.Plugins.Popup awaitable
  • A Rg.Plugins.Popup awaitable with entry

Xamarin Forms popup

To create a Xamarin Forms popup you can use this kind of code:

Application.Current.MainPage.DisplayAlert(AppResource.Attention, AppResource.XamarinFormsPopup, AppResource.Ok);

With this code you have these result:

When you hit “ok”, you can see that the popup waits for it to close before proceeding to the next instruction.

It works, but the truck driver has big fingers, and the “OK” button is too small. And I don’t know how to customize it: maybe with some Custom Renderers…

Not awaitable Rg.Plugins.Popup

To create a popup using Rg.Plugins.Popup, you can follow this tutorial: https://github.com/rotorgames/Rg.Plugins.Popup/wiki/PopupPage. I have create a class that inherit PopUp, add some Labels, a ViewModel, and use it in this way:

await Rg.Plugins.Popup.Services.PopupNavigation.Instance.PushAsync(new DisplayAlertPage(AppResource.Attention, AppResource.RGNotAwaitablePopup, DisplayAlertViewModel.EnumInputType.Ok));

When I run it, I have this sequence:

Then, when I press “OK”, I see the popup:

Obviously this is not the result I would expect. First I would like to see the popup of Rg.Plugins.Popup and then, after pressing “OK”, see the second popup. This example shows that Rg.Plugins.Popup does not wait for it to close before executing the next statement.

Awaitable Rg.Plugins.Popup

To visualize an awaitable popup, I have used https://docs.microsoft.com/en-us/dotnet/api/system.threading.tasks.taskcompletionsource?view=net-5.0. You can take a look to https://github.com/acaliaro/XamFormsAwaitablePopup/blob/main/XamFormsAwaitablePopup/Page/DisplayAlertPage.xaml.cs:

    [XamlCompilation(XamlCompilationOptions.Compile)]
    public partial class DisplayAlertPage : Rg.Plugins.Popup.Pages.PopupPage
    {

        private TaskCompletionSource<Tuple<DisplayAlertViewModel.EnumOutputType, string>> _taskCompletionSource;
        public Task<Tuple<DisplayAlertViewModel.EnumOutputType, string>> PopupClosedTask => _taskCompletionSource.Task;

 
        public DisplayAlertPage(string title, string message, DisplayAlertViewModel.EnumInputType inputType)
        {

            InitializeComponent();
            BindingContext = new DisplayAlertViewModel(title, message, inputType);

        }

        protected override void OnAppearing()
        {

            base.OnAppearing();
            _taskCompletionSource = new TaskCompletionSource<Tuple<DisplayAlertViewModel.EnumOutputType, string>>();

        }

        protected override void OnDisappearing()
        {

            base.OnDisappearing();          
            _taskCompletionSource.SetResult(((DisplayAlertViewModel)BindingContext).ReturnValue);

        }
    }

In this code, I use TaskCompletionSource which helps us wait for the popup to close before proceeding to the next statement. I define the output type using a Tuple (you can also have your own Class) and a string in the case your popup allows to insert a value (eg: a password).

When the execution reach the “OnDisappearing” method, the TaskCompletionSource’s SetResult is set and your calling code has the result of the user interaction.

After pressing “OK”, the second popup appears that has waited for the first to close.

To visualize the popup you can use this code:

var popup = new DisplayAlertPage(AppResource.Attention, AppResource.RGAwaitablePopup, DisplayAlertViewModel.EnumInputType.Ok);             

await Rg.Plugins.Popup.Services.PopupNavigation.Instance.PushAsync(popup);             
var ret = await popup.PopupClosedTask;              

await Application.Current.MainPage.DisplayAlert(AppResource.Attention, AppResource.IsAwaitable, AppResource.Ok);

Awaitable Rg.Plugins.Popup with entry

The last example demonstrates how to make a popup appear and allow the entry of a value (for example a password):

You can enter a value in the entry control, the press “OK” or “CANCEL”: the next popup will visualize your choices:

To visualize the popup and the response, you can use this code:

var popup = new DisplayAlertPage(AppResource.Attention, AppResource.RGAwaitableWithEntryPopup, DisplayAlertViewModel.EnumInputType.OkCancelWithInput);             

await Rg.Plugins.Popup.Services.PopupNavigation.Instance.PushAsync(popup);             
var ret = await popup.PopupClosedTask;              

await Application.Current.MainPage.DisplayAlert(AppResource.Attention, AppResource.IsAwaitable + " with this value: " + ret.Item2 + " and this button pressed: " + ret.Item1.ToString(), AppResource.Ok);

Conclusions

Xamarin Forms has it’s own popup control but it seems to be not very customizable. Rg.Plugins.Popup is customizable but to have it awaitable you have to add some code.

I hope I have easily described how to have this popup awaitable. For any questions, you can comment on this post. The demo I put on Github was only tested on Android, but I think it also works on iOS and UWP without any particular changes. Merry Christmas everyone !!!

Rispondi

Inserisci i tuoi dati qui sotto o clicca su un'icona per effettuare l'accesso:

Logo di WordPress.com

Stai commentando usando il tuo account WordPress.com. Chiudi sessione /  Modifica )

Google photo

Stai commentando usando il tuo account Google. Chiudi sessione /  Modifica )

Foto Twitter

Stai commentando usando il tuo account Twitter. Chiudi sessione /  Modifica )

Foto di Facebook

Stai commentando usando il tuo account Facebook. Chiudi sessione /  Modifica )

Connessione a %s...