Messagebox.Show and DialogResult equivalent in MonoTouch
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).
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;
}
Scarlaxx
Updated on June 09, 2022Comments
-
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 over 13 yearsiOS unfortunately allows modal dialogs: that's what Apple uses for its own Push Notification alerts.
-
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 over 13 yearsOne 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 over 12 yearsAm 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 about 11 yearsI 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 almost 11 yearsthis is a very nice implementation of MessageBox and saves me time writing code all the time!
-
Prashant Cholachagudda about 10 years