Messagebox.Show and DialogResult equivalent in MonoTouch

11,049

Solution 1

To do this, what you can do is to run the mainloop manually. I have not managed to stop the mainloop directly, so I instead run the mainloop for 0.5 seconds and wait until the user responds.

The following function shows how you could implement a modal query with the above approach:

int WaitForClick ()
{
    int clicked = -1;
    var x = new UIAlertView ("Title", "Message",  null, "Cancel", "OK", "Perhaps");
    x.Show ();
    bool done = false;
    x.Clicked += (sender, buttonArgs) => {
        Console.WriteLine ("User clicked on {0}", buttonArgs.ButtonIndex);
    clicked = buttonArgs.ButtonIndex;
    };    
    while (clicked == -1){
        NSRunLoop.Current.RunUntil (NSDate.FromTimeIntervalSinceNow (0.5));
        Console.WriteLine ("Waiting for another 0.5 seconds");
    }

    Console.WriteLine ("The user clicked {0}", clicked);
    return clicked;
}

Solution 2

Based on the Miguel's coded, here is a convenient replacement of standard MessageBox:

using System;
using System.Drawing;
using MonoTouch.UIKit;
using MonoTouch.Foundation;
using System.Collections.Generic;

namespace YourNameSpace
{

    public enum MessageBoxResult
    {
        None = 0,
        OK,
        Cancel,
        Yes,
        No
    }

    public enum MessageBoxButton
    {
        OK = 0,
        OKCancel,
        YesNo,
        YesNoCancel
    }

    public static class MessageBox
    {
        public static MessageBoxResult Show(string messageBoxText, string caption, MessageBoxButton buttonType)
        {
            MessageBoxResult res = MessageBoxResult.Cancel;
            bool IsDisplayed = false;
            int buttonClicked = -1;
            MessageBoxButton button = buttonType;
            UIAlertView alert = null;

            string cancelButton = "Cancel";
            string[] otherButtons = null;

            switch (button)
            {
                case MessageBoxButton.OK:
                    cancelButton = "";
                    otherButtons = new string[1];
                    otherButtons[0] = "OK";
                    break;

                case MessageBoxButton.OKCancel:
                    otherButtons = new string[1];
                    otherButtons[0] = "OK";
                    break;

                case MessageBoxButton.YesNo:
                    cancelButton = "";
                    otherButtons = new string[2];
                    otherButtons[0] = "Yes";
                    otherButtons[1] = "No";
                    break;

                case MessageBoxButton.YesNoCancel:
                    otherButtons = new string[2];
                    otherButtons[0] = "Yes";
                    otherButtons[1] = "No";
                    break;
            }

            if (cancelButton.Length > 0)
                alert = new UIAlertView(caption, messageBoxText, null, cancelButton, otherButtons);
            else
                alert = new UIAlertView(caption, messageBoxText, null, null, otherButtons);

            alert.BackgroundColor = UIColor.FromWhiteAlpha(0f, 0.8f);
            alert.Canceled += (sender, e) => {
                buttonClicked = 0;
                IsDisplayed = false;
            };

            alert.Clicked += (sender, e) => {
                buttonClicked = e.ButtonIndex;
                IsDisplayed = false;
            };

            alert.Dismissed += (sender, e) => {
                if (IsDisplayed)
                {
                    buttonClicked = e.ButtonIndex;
                    IsDisplayed = false;
                }
            };

            alert.Show();

            IsDisplayed = true;

            while (IsDisplayed)
            {
                NSRunLoop.Current.RunUntil (NSDate.FromTimeIntervalSinceNow (0.2));
            }

            switch (button)
            {
                case MessageBoxButton.OK:
                    res = MessageBoxResult.OK;
                    break;

                case MessageBoxButton.OKCancel:
                    if (buttonClicked == 1)
                        res = MessageBoxResult.OK;
                    break;

                case MessageBoxButton.YesNo:
                    if (buttonClicked == 0)
                        res = MessageBoxResult.Yes;
                    else
                        res = MessageBoxResult.No;
                    break;

                case MessageBoxButton.YesNoCancel:
                    if (buttonClicked == 1)
                        res = MessageBoxResult.Yes;
                    else if (buttonClicked == 2)
                        res = MessageBoxResult.No;
                    break;
            }

            return res;
        }

        public static MessageBoxResult Show(string messageBoxText)
        {
            return Show(messageBoxText, "", MessageBoxButton.OK);
        }

        public static MessageBoxResult Show(string messageBoxText, string caption)
        {
            return Show(messageBoxText, caption, MessageBoxButton.OK);
        }
    }
}

Solution 3

I think this approach using async/await is much better, and doesn't suffer from freezing the app when rotating the device, or when the autoscrolling interferes and leaves you stuck in the RunUntil loop forever without the ability to click a button (at least these problems are easy to reproduce on iOS7).

Modal UIAlertView

Task<int> ShowModalAletViewAsync (string title, string message, params string[] buttons)
{
    var alertView = new UIAlertView (title, message,  null, null, buttons);
    alertView.Show ();
    var tsc = new TaskCompletionSource<int> ();

    alertView.Clicked += (sender, buttonArgs) => {
        Console.WriteLine ("User clicked on {0}", buttonArgs.ButtonIndex);      
        tsc.TrySetResult(buttonArgs.ButtonIndex);
    };    
    return tsc.Task;
}       
Share:
11,049
Scarlaxx
Author by

Scarlaxx

Updated on June 09, 2022

Comments

  • Scarlaxx
    Scarlaxx almost 2 years

    I have a Yes/No dialog from UIAlertView with two buttons. I would like in my method to implement the logic similar to this:

    if(messagebox.Show() == DialogResult.OK)
    

    The thing is if I call UIAlertView.Show() the process continues. But I need to wait for the result of user interaction and return true or false depanding on clicking the second button. Is this possible in MonoTouch?

  • ptnik
    ptnik over 13 years
    iOS unfortunately allows modal dialogs: that's what Apple uses for its own Push Notification alerts.
  • Akash Kava
    Akash Kava over 13 years
    @ptnik that may be used by Apple internally, but if they will allow modal dialogs, it will create problems.
  • Krumelur
    Krumelur over 13 years
    One up becaue I have been looking for a way to do this for so long and got a couple of "no can do" answers - and then comes Miguel! :-)
  • John Sonmez
    John Sonmez over 12 years
    Am I correct in saying that MonoDevelop doesn't currently identify the type buttonArgs as UIButtonArgs in this case (inside the Lambda?) I am seeing that I just wanted to make sure. (For auto-complete. Not seeing it showing ButtonIndex, seems to be treating it as a Object.)
  • Doug Null
    Doug Null about 11 years
    I got this error when doing this on MonoDevelop 3.1.1: [ERROR] FATAL UNHANDLED EXCEPTION: MonoTouch.UIKit.UIKitThreadAccessException: UIKit Consistency error: you are calling a UIKit method that can only be invoked from the UI thread.
  • jharr100
    jharr100 almost 11 years
    this is a very nice implementation of MessageBox and saves me time writing code all the time!
  • Prashant Cholachagudda
    Prashant Cholachagudda about 10 years
    using async/await is lot easier than using NSRunLoop prashantvc.com/modal-uialertview-ios-7