Question

We are using a static Alert Dialog to get confirmation from the user for certain actions. In our call to Show() we want to keep control until the user clicks a button so that we can return the button click result at the end of the Show() call.

Our iOS version (a UIAlertView) uses

while (displayed)
{
    MonoTouch.Foundation.NSRunLoop.Current.RunUntil(
            MonoTouch.Foundation.NSDate.FromTimeIntervalSinceNow(0.2));
}

in its Show() method to wait for user input prior to returning their button selection as a result.

Is there an Android equivalent to this that we can leverage in Monodroid?

Was it helpful?

Solution

Solved via a different design:

Instead of waiting for the user to interact with the dialog, and blocking everything else, we instead provide an EventHandler in our call to the static Show method that fires when the user clicks a button:

public static void Show(string title, 
                        string message, 
                        Context context,
                        EventHandler handler,
                        ConfirmationAlertButton button) { ... }

We maintain a private reference to the passed in EventHandler that gets triggered on the button click like so:

private static void OkClicked(object sender, DialogClickEventArgs e)
{
    if (_handler != null)
    {
        _handler.Invoke(sender, e);
    }

    _instance.Dismiss();
    _instance = null;
    _handler = null;
}

Here is an example of what a call to Show looks like from an Activity:

ConfirmationDialog.Show(@"Message title",
                        @"Message text",
                        this,
                        delegate
                        {
                            if (e.Result)
                            {
                                Finish();
                            }
                            else
                            {
                                Invalidate();
                            }
                        },
                        ConfirmationAlertButton.OK);

If anyone would like more information on using a static dialog in their Xamarin Android application, just let me know!

OTHER TIPS

I've solved this problem by creating a AlertDialogHelper class that shows the dialog for me. Just wanted to share my solution with you guys.

Helper class

public class AlertDialogHelper : Java.Lang.Object, IDialogInterfaceOnDismissListener
{
    Context context;
    ManualResetEvent waitHandle;
    string title;
    string message;
    string positiveButtonCaption;
    string negativeButtonCaption;
    bool dialogResult;

    public static async Task<bool> ShowAsync(Context context, string title, string message)
    {
        return await AlertDialogHelper.ShowAsync(context, title, message, "OK", "Cancel");
    }

    public static async Task<bool> ShowAsync(Context context, string title, string message, string positiveButton, string negativeButton)
    {
        return await new AlertDialogHelper(context, title, message, positiveButton, negativeButton).ShowAsync();
    }

    private AlertDialogHelper(Context context, string title, string message, string positiveButton, string negativeButton)
    {
        this.context = context;
        this.title = title;
        this.message = message;
        this.positiveButtonCaption = positiveButton;
        this.negativeButtonCaption = negativeButton;
    }

    private async Task<bool> ShowAsync()
    {
        this.waitHandle = new ManualResetEvent(false);
        new AlertDialog.Builder(this.context)
            .SetTitle(this.title)
            .SetMessage(this.message)
            .SetPositiveButton(this.positiveButtonCaption, OnPositiveClick)
            .SetNegativeButton(this.negativeButtonCaption, OnNegativeClick)
            .SetOnDismissListener(this)
            .Show();

        Task<bool> dialogTask = new Task<bool>(() =>
        {
            this.waitHandle.WaitOne();
            return this.dialogResult;
        });
        dialogTask.Start();
        return await dialogTask;
    }

    private void OnPositiveClick(object sender, DialogClickEventArgs e)
    {
        this.dialogResult = true;
        this.waitHandle.Set();
    }

    private void OnNegativeClick(object sender, DialogClickEventArgs e)
    {
        this.dialogResult = false;
        this.waitHandle.Set();
    }

    public void OnDismiss(IDialogInterface dialog)
    {
        this.dialogResult = false;
        this.waitHandle.Set();
    }
}

Usage

// Default buttons
bool dialogResult = await AlertDialogHelper.ShowAsync(this, "Dialog title", "Some informative message.");

// Custom buttons
bool dialogResult = await AlertDialogHelper.ShowAsync(this, "Dialog title", "Some informative message.", "Yes", "No");

You will have to do 2 things. First override the back button to keep the user from backing off the activity. Second you will have to create a custom dialog that keeps re-opening until the user performs the correct action. This is because the user can touch outside the dialog to cancel it without using the buttons on the bottom of the dialog.

Here is a link to a previous post on creating the custom dialog

The sample is in java. If you need help translating to C# I can give you an example.

Here is how you override the back button.

public override bool OnKeyDown(Keycode keyCode, KeyEvent e)
    {
        if (keyCode == Keycode.Back && awaitConfirmation)
            return true;
        else
            return base.OnKeyDown(keyCode, e);
    }

The awaitConfirmation variable would be a local variable (defaulted to false) that would be set to true before showing the dialog and set back to false when the user had accepted confirmation.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top