我有一个带有两个按钮的UIAlertView的是/否对话框。我希望在我的方法中实现类似于此的逻辑:
if(messagebox.Show() == DialogResult.OK)
问题是,如果我调用UIAlertView.Show(),该过程将继续。但我需要等待用户交互的结果,并在单击第二个按钮时返回true或false depanding。这在MonoTouch中是否可行?
答案 0 :(得分:18)
要做到这一点,你可以做的是手动运行mainloop。我没有设法直接停止主循环,所以我改为运行主循环0.5秒并等待用户响应。
以下函数显示了如何使用上述方法实现模态查询:
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;
}
答案 1 :(得分:17)
基于Miguel的编码,这里是标准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);
}
}
}
答案 2 :(得分:1)
我认为使用async / await的这种方法要好得多,并且在旋转设备时不会冻结应用程序,或者当自动滚动干扰并让你永远陷入RunUntil循环而无法点击按钮时(至少这些问题很容易在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;
}
答案 3 :(得分:0)
MonoTouch(iOS)没有模态对话框,原因是模态对话框(等待)会导致死锁,因此像Silverlight,Flex / Flash,iOS这样的框架不允许这样的对话框。
你可以使用它的唯一方法是,你必须将一个委托传递给UIAlertView,它将在成功时被调用。我不知道UIAlertView的确切语法,但您应该看到有关UIAlertView的文档,必须有一种方法来传递实现UIAlertViewDelegate协议/接口的类。这将有一个方法,将在完成对话框时调用。
答案 4 :(得分:0)
danmiser和Ales&#39;答案
using System;
using System.Drawing;
using MonoTouch.UIKit;
using MonoTouch.Foundation;
using System.Collections.Generic;
using System.Threading.Tasks;
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 Task<MessageBoxResult> ShowAsync(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;
}
var tsc = new TaskCompletionSource<MessageBoxResult> ();
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) => {
tsc.TrySetResult( MessageBoxResult.Cancel);
};
alert.Clicked += (sender, e) => {
buttonClicked = e.ButtonIndex;
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;
}
tsc.TrySetResult( res);
};
alert.Show();
return tsc.Task;
}
public static Task<MessageBoxResult> ShowAsync(string messageBoxText)
{
return ShowAsync(messageBoxText, "", MessageBoxButton.OK);
}
public static Task<MessageBoxResult> ShowAsync(string messageBoxText, string caption)
{
return ShowAsync(messageBoxText, caption, MessageBoxButton.OK);
}
}
}
答案 5 :(得分:0)
这是另一个更新,基于Miguel,Ales,danmister和Patrick的贡献。
自从iOS 11发布以来,特别是版本11.1.2(我第一次注意到它),我发布的原始解决方案(Ales)变得不可靠,开始随机冻结。这个使用显式调用的NSRunLoop.Current.RunUntil()。
所以我更新了我的原始类,实际上提供了同步和异步方法,并进行了一些其他更改,以便在单击任何按钮后立即释放内存,还添加了代码,如果Windows CRLF将文本对齐到左侧检测到换行符。
命名空间:
using System;
using CoreGraphics;
using UIKit;
using Foundation;
using System.Collections.Generic;
using System.Threading.Tasks;
代码:
public enum MessageBoxResult
{
None = 0,
OK,
Cancel,
Yes,
No
}
public enum MessageBoxButton
{
OK = 0,
OKCancel,
YesNo,
YesNoCancel
}
public static class MessageBox
{
/* This class emulates Windows style modal boxes. Unfortunately, the original code doesn't work reliably since cca iOS 11.1.2 so
* you have to use the asynchronous methods provided here.
*
* The code was a bit restructured utilising class MessageBoxNonstatic to make sure that on repeated use, it doesn't allocate momere memory.
* Note that event handlers are explicitly removed and at the end I explicitly call garbage collector.
*
* The code is a bit verbose to make it easier to understand and open it to tweaks.
*
*/
// Synchronous methods - don't work well since iOS 11.1.2, often freeze because something has changed in the event loop and
// NSRunLoop.Current.RunUntil() is not reliable to use anymore
public static MessageBoxResult Show(string messageBoxText, string caption, MessageBoxButton buttonType)
{
MessageBoxNonstatic box = new MessageBoxNonstatic();
return box.Show(messageBoxText, caption, buttonType);
}
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);
}
// Asynchronous methods - use with await keyword. Restructure the calling code tho accomodate async calling patterns
// See https://docs.microsoft.com/en-us/dotnet/csharp/async
/*
async void DecideOnQuestion()
{
if (await MessageBox.ShowAsync("Proceed?", "DECIDE!", MessageBoxButton.YesNo) == MessageBoxResult.Yes)
{
// Do something
}
}
*/
public static Task<MessageBoxResult> ShowAsync(string messageBoxText, string caption, MessageBoxButton buttonType)
{
MessageBoxNonstatic box = new MessageBoxNonstatic();
return box.ShowAsync(messageBoxText, caption, buttonType);
}
public static Task<MessageBoxResult> ShowAsync(string messageBoxText)
{
return ShowAsync(messageBoxText, "", MessageBoxButton.OK);
}
public static Task<MessageBoxResult> ShowAsync(string messageBoxText, string caption)
{
return ShowAsync(messageBoxText, caption, MessageBoxButton.OK);
}
}
public class MessageBoxNonstatic
{
private bool IsDisplayed = false;
private int buttonClicked = -1;
private UIAlertView alert = null;
private string messageBoxText = "";
private string caption = "";
private MessageBoxButton button = MessageBoxButton.OK;
public bool IsAsync = false;
TaskCompletionSource<MessageBoxResult> tsc = null;
public MessageBoxNonstatic()
{
// Do nothing
}
public MessageBoxResult Show(string sMessageBoxText, string sCaption, MessageBoxButton eButtonType)
{
messageBoxText = sMessageBoxText;
caption = sCaption;
button = eButtonType;
IsAsync = false;
ShowAlertBox();
WaitInLoopWhileDisplayed();
return GetResult();
}
public Task<MessageBoxResult> ShowAsync(string sMessageBoxText, string sCaption, MessageBoxButton eButtonType)
{
messageBoxText = sMessageBoxText;
caption = sCaption;
button = eButtonType;
IsAsync = true;
tsc = new TaskCompletionSource<MessageBoxResult>();
ShowAlertBox();
return tsc.Task;
}
private void ShowAlertBox()
{
IsDisplayed = false;
buttonClicked = -1;
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;
}
IUIAlertViewDelegate d = null;
if (cancelButton.Length > 0)
alert = new UIAlertView(caption, messageBoxText, d, cancelButton, otherButtons);
else
alert = new UIAlertView(caption, messageBoxText, d, null, otherButtons);
if (messageBoxText.Contains("\r\n"))
{
foreach (UIView v in alert.Subviews)
{
try
{
UILabel l = (UILabel)v;
if (l.Text == messageBoxText)
{
l.TextAlignment = UITextAlignment.Left;
}
}
catch
{
// Do nothing
}
}
}
alert.BackgroundColor = UIColor.FromWhiteAlpha(0f, 0.8f);
alert.Canceled += Canceled_Click;
alert.Clicked += Clicked_Click;
alert.Dismissed += Dismissed_Click;
alert.Show();
IsDisplayed = true;
}
// ======================================================================= Private methods ==========================================================================
private void WaitInLoopWhileDisplayed()
{
while (IsDisplayed)
{
NSRunLoop.Current.RunUntil(NSDate.FromTimeIntervalSinceNow(0.2));
}
}
private void Canceled_Click(object sender, EventArgs e)
{
buttonClicked = 0;
IsDisplayed = false;
DisposeAlert();
}
private void Clicked_Click(object sender, UIButtonEventArgs e)
{
buttonClicked = (int)e.ButtonIndex;
IsDisplayed = false;
DisposeAlert();
}
private void Dismissed_Click(object sender, UIButtonEventArgs e)
{
if (IsDisplayed)
{
buttonClicked = (int)e.ButtonIndex;
IsDisplayed = false;
DisposeAlert();
}
}
private void DisposeAlert()
{
alert.Canceled -= Canceled_Click;
alert.Clicked -= Clicked_Click;
alert.Dismissed -= Dismissed_Click;
alert.Dispose();
alert = null;
GC.Collect();
if (IsAsync)
GetResult();
}
private MessageBoxResult GetResult()
{
MessageBoxResult res = MessageBoxResult.Cancel;
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;
}
if (IsAsync)
tsc.TrySetResult(res);
return res;
}
}